Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CodeMash 2020 - Kotlin for C# Developers

CodeMash 2020 - Kotlin for C# Developers

Dive into the latest craze in languages and platforms - Kotlin. This time we will be looking at it from the perspective of a .NET C# developer, draw comparisons between the languages, and bridge the gap between these 2 amazing languages.

We'll look at:
- Kotlin as a language
- Platforms Kotlin is great for
- Object Oriented Implementations in Kotlin
- Extended Features
- Features Kotlin has that C# doesn't
- A demo Android application in Kotlin vs a Xamarin.Android app in C#

In the end you will leave with a foundational knowledge of Kotlin and its capabilities to build awesome apps with less code. You should feel comfortable comparing C# applications to Kotlin applications and know where to find resources to learn even more!

Avatar for Alex Dunn - SuavePirate

Alex Dunn - SuavePirate

January 09, 2020
Tweet

More Decks by Alex Dunn - SuavePirate

Other Decks in Programming

Transcript

  1. • Statically Typed • Object Oriented AND Functional Style support

    • Runs on the Java Virtual Machine • Can also compile to JavaScript and Native Kotlin
  2. • Reduce Verbosity • Support many styles of programming •

    Backwards Compatibility • Faster Development Cycle Primary Goals
  3. “Kotlin is inspired by existing languages such as Java, C#,

    JavaScript, Scala and Groovy” ~ kotlinlang.org
  4. public class Dog { public string Name { get; set;

    } public int Age { get; set; } public string Breed { get; set; } } class Dog() { var name: String? = null var age: Int? = null var breed: String? = null } POCO / POJO / POKO
  5. public class Dog { public string Name { get; set;

    } public int Age { get; set; } public string Breed { get; set; } public Dog() { } public Dog(string name, int age, string breed) { Name = name; Age = age; Breed = breed; } } class Dog() { constructor( name: String?, age: Int?, breed: String?) : this() { this.name = name this.age = age this.breed = breed } var name: String? = null var age: Int? = null var breed: String? = null } Constructor Overrides
  6. Kotlin Only – Data Classes data class Dog(val name: String,

    val age: Int, val breed: String) val dog1 = Dog("Bentley", 5, "Staffordshire Terrier") val dog1Copy = dog1.copy() val areSame = dog1 == dog1Copy // true
  7. Kotlin Only – val and var class Dog { var

    name: String? = null val readonlyName: String = "A name" fun bark() { val sound = "boof!" var sound2 = "roof!" sound2 = "woof!" // ok sound = "woof" // not ok } }
  8. public class Dog { public string Name { get; set;

    } public string Breed { get; set; } public DateTime BirthDate { get; set; } public int Age { get => (DateTime.Now - BirthDate).Days / 365; } } class Dog { var name: String? = null var birthDate: Date = Date() var breed: String? = null val age: Int get() = (((Date().time - birthDate.time) / (1000 * 60 * 60 * 24)) / 365) as Int } Getters and Setters
  9. public class DogAdoptionService { public void AdoptDog(Dog dog) { //

    run some business logic to adopt the dog } public AdoptableDog AdoptDog(AdoptableDog dog) { dog.IsAdopted = true; return dog; } } public class AdoptableDog { public string Name { get; set; } public bool IsAdopted { get; set; } public AdoptableDog(string name) { Name = name; } } data class AdoptableDog(val name: String) { var isAdopted: Boolean = false; } class DogAdoptionService { fun adoptDog(dog: Dog) { // run some business logic to adopt the dog } fun adoptDog(dog: AdoptableDog): AdoptableDog { dog.isAdopted = true return dog } } DogAdoptionService() .adoptDog(Dog("Ryder", 2, "Mix Breed")) DogAdoptionService() .adoptDog(AdoptableDog("Ryder")) Methods / Functions
  10. public class Dog { public string Name { get; set;

    } public Breed Breed { get; set; } public int BreedLifespan => Breed?.AverageLifespan ?? 0; public int DangerousLifespan => Breed.AverageLifespan.Value; } public class Breed { public string Name { get; set; } public int? AverageLifespan { get; set; } } data class Dog(val name: String) { var breed: Breed? = null val breedLifespan get() = breed?.averageLifeSpan ?: 0 val dangerousLifespan get() = breed!!.averageLifeSpan!! } data class Breed(val name: String, val averageLifeSpan: Int?) Null Coalescing and Propagation
  11. public class Dog { public string Name { get; set;

    } public int Age { get; set; } public string Breed { get; set; } } class Dog() { var name: String? = null var age: Int? = null var breed: String? = null } OO Foundation
  12. public interface IAdoptionService { void AdoptDog(AdoptableDog dog); // C# 7

    doesn't have interface implementations void AdoptDogs(List<AdoptableDog> dogs); } public class DogAdoptionService : IAdoptionService { public void AdoptDog(AdoptableDog dog) { dog.IsAdopted = true; } public void AdoptDogs(List<AdoptableDog> dogs) { foreach(var dog in dogs) { AdoptDog(dog); } } } interface DogAdoptionService { fun adoptDog(dog: AdoptableDog) fun adoptDogs(dogs: List<AdoptableDog>) { for(dog in dogs) { adoptDog(dog) } } } class DogAdoptionServiceImpl() : DogAdoptionService { override fun adoptDog(dog: AdoptableDog) { dog.isAdopted = true } } Interfaces
  13. public class Dog { public string Name { get; set;

    } protected int _age; private Breed _breed; private class Breed { public string Name { get; set; } } } open class Dog { var name: String? = null private var breed: Breed? = null protected var age: Int? = null private data class Breed(val name: String) } Encapsulation
  14. public abstract class AdoptionService { public abstract void AdoptDog(AdoptableDog dog);

    public void AdoptDogs(List<AdoptableDog> dogs) { foreach(var dog in dogs) { AdoptDog(dog); } } } public class DogAdoptionService : AdoptionService { public override void AdoptDog(AdoptableDog dog) { dog.IsAdopted = true; } } abstract class AdoptionService { abstract fun adoptPet(pet: AdoptablePet) fun adoptPets(pets: List<AdoptablePet>) { for(pet in pets) { adoptPet(pet) } } } class DogAdoptionService : AdoptionService() { override fun adoptPet(pet: AdoptablePet) { pet.isAdopted = true } } Abstract Classes
  15. public static class AdoptionHelper { public static void AdoptPet(AdoptablePet pet)

    { pet.IsAdopted = true; } } object AdoptionHelper { fun adoptPet(pet: AdoptablePet) { pet.isAdopted = true; } } Static Objects
  16. public class AdoptionService { public void InstanceAdopt(AdoptablePet pet) { pet.IsAdopted

    = true; } public static void StaticAdopt(AdoptablePet pet) { pet.IsAdopted = true; } } // ... AdoptionService.StaticAdopt(new AdoptablePet { IsAdopted = false }); new AdoptionService().InstanceAdopt(new AdoptablePet { IsAdopted = false }); class AdoptionService { fun instanceAdopt(pet: AdoptablePet) { pet.isAdopted = true } // static companion object { fun staticAdopt(pet: AdoptablePet) { pet.isAdopted = true } } } fun run() { AdoptionService.staticAdopt(AdoptablePet(false)) AdoptionService().instanceAdopt(AdoptablePet(false)) } Static Members
  17. public class AdoptionService { public void AdoptDog(AdoptableDog dog) { dog.Adopt();

    } } public static class AdoptableExtensions { public static void Adopt(this AdoptableDog dog) { dog.IsAdopted = true; } } class AdoptionService { fun adoptDog(dog: AdoptableDog) { dog.adopt() } } // extension functions fun AdoptableDog.adopt() { this.isAdopted = true } Extensions
  18. public class PetAdoptionService { public void Adopt(dynamic pet) { pet.IsAdopted

    = true; } } class PetAdoptionService { // not supported in jvm fun adoptPet(pet: dynamic) { pet.isAdopted = true } } Dynamic Types
  19. public List<AdoptablePet> Pets { get; set; } public void AdoptPet(string

    id) { var petExists = PetExists(p => p.Id == id); // do something to get pet info } public bool PetExists( Expression<Func<AdoptablePet, bool>> predicate) { return Pets.Any(predicate.Compile()); } var pets: List<AdoptablePet>? = null fun adoptPet(id: String) { val petExists = petExists { p -> p.id == id } // do something to get pet info } fun petExists(predicate: (AdoptablePet) -> Boolean) : Boolean { return pets!!.any(predicate) } Type Inference
  20. public class PetAdoptionService<T> where T : AdoptablePet { public void

    AdoptPet(T pet) { pet.IsAdopted = true; } } public class AdoptablePet { public bool IsAdopted { get; set; } } class PetAdoptionService<T : AdoptablePet> { fun adoptPet(pet: T) { pet.isAdopted = true } } class AdoptablePet(var isAdopted: Boolean) Generics
  21. public class DogAdoptionService { public void Adopt((Dog, Shelter) data) {

    data.Item1.IsAdopted = true; } } public class Dog { public bool IsAdopted { get; set; } } public class Shelter { } class DogAdoptionService { fun adopt(data: Pair<Dog, Shelter>) { data.first.isAdopted = true } } data class Dog(var isAdopted: Boolean) class Shelter() Tuples
  22. public class DogAdoptionService { public async Task BackgroundGet() { await

    GetAdoptableDogsAsync(); } } class DogAdoptionService { fun BackgroundGet() { // launch coroutine GlobalScope.launch { getAdoptableDogs() } } } Asynchronous Code Execution
  23. public class DogAdoptionService { public async Task<List<AdoptableDog>> GetAdoptableDogsAsync() { var

    dogJson = await new HttpClient().GetStringAsync("http://someurl.com"); return JsonConvert.DeserializeObject<List<AdoptableDog>>(dogJson); } public void BackgroundGet() { List<AdoptableDog> dogs; Task.Run(async () => dogs = await GetAdoptableDogsAsync()); } } C# Async Await
  24. Kotlin Coroutines class DogAdoptionService { fun getAdoptableDogs(): List<AdoptableDog> { var

    json = URL("http://someurl.com").readText() val listType = object : TypeToken<List<AdoptableDog>>() { }.type return Gson().fromJson(json, listType) } fun getAdoptableDogsInBackground() { var dogs: List<AdoptableDog>? = null GlobalScope.launch { dogs = getAdoptableDogs() } } }
  25. “Awaiting” a Coroutine class DogAdoptionService { fun getAdoptableDogs(): List<AdoptableDog> {

    var json = URL("http://someurl.com").readText() val listType = object : TypeToken<List<AdoptableDog>>() { }.type return Gson().fromJson(json, listType) } fun getAdoptableDogsInBackground() { var dogs: List<AdoptableDog>? = null val task = GlobalScope.launch { dogs = getAdoptableDogs() } task.join() // waits for coroutine to complete } }
  26. public class Dog { public string? Name { get; set;

    } public int? Age { get; set; } public string? Breed { get; set; } } class Dog() { var name: String? = null var age: Int? = null var breed: String? = null } Nullable Reference Types
  27. void GetNamesByRange(List<Dog> dogs) { foreach(var dog in dogs[1..4]) { Console.WriteLine(dog.Name);

    } } fun getNamesByRange(dogs: List<Dog>) { val range = 1..4 for(dog in dogs.subList(range.first, range.last)) { print(dog.name) } } Ranges
  28. public interface IAdoptionService { void AdoptDog(AdoptableDog dog); public void AdoptDogs(List<AdoptableDog>

    dogs) { foreach(var dog in dogs) { AdoptDog(dog); } } } public class DogAdoptionService : IAdoptionService { public void AdoptDog(AdoptableDog dog) { dog.IsAdopted = true; } } interface DogAdoptionService { fun adoptDog(dog: AdoptableDog) fun adoptDogs(dogs: List<AdoptableDog>) { for(dog in dogs) { adoptDog(dog) } } } class DogAdoptionServiceImpl() : DogAdoptionService { override fun adoptDog(dog: AdoptableDog) { dog.isAdopted = true } } Default Interface Implementations
  29. async IAsyncEnumberable<string> GetNamesAsync(List<Dog> dogs) { foreach(var dog in dogs) {

    await Task.Delay(200); yield return dog.Name; } } public async Task RunAsync(List<Dog> dogs) { foreach(var name in GetNamesAsync(dogs)) { Console.WriteLine(name); } } fun CoroutineScope.asyncName(dog: Dog) = async { delay(200) dog.name } fun CoroutineScope.asyncNames(dogs: List<Dog>) : List<Deferred<String?>> { return dogs.map {d -> asyncName(d)} } fun main(dogs: List<Dog>) = runBlocking { val names = asyncNames(dogs) for(name in names) { println(name.await()) } } Asynchronous Streams
  30. Surface Scratched-ish • Functional Language Features • Design Patterns and

    Practices • Deeper language features • Ktor • Async/Await with Coroutines • Anko • Native • JavaScript • Android Tools
  31. Resources • Source: https://github.com/JetBrains/kotlin • Examples: https://github.com/SuavePirate/KotlinForCSharp • Pluralsight Course:

    https://app.pluralsight.com/library/courses/building-android-apps- kotlin-getting-started • Blog posts at https://alexdunn.org • Slides will be announced on Twitter @Suave_Pirate!