3

How programming C# translates to Kotlin

 3 years ago
source link: https://www.devbridge.com/articles/how-programming-c-translates-vs-kotlin/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

How programming C# translates to Kotlin

Simona Mockutė-Kazlauskė

Using one programming language to learn another

For anyone fluent or familiar with multiple languages, you likely know that the elements behind one language apply to and help learn others. I look at programming languages similarly—aspects frequently carry over from one language to another. Being knowledgeable in multiple programming languages is an extremely useful skill for developers. Sometimes we (developers) need to know how to move from one language to another when working in another field, with different technologies, or on a new project. In this article, I’ll go over how C# and Kotlin translate to each other.

What is C#?

C# is a programming language mostly used for backend development (API). However, it’s also used to create full web applications with an ASP.NET Core MVC framework and HTML. In order to easily transfer the code to mobile development, one can use Xamarin, a cross-platform mobile UI framework that’s used for building iOS and Android apps. A good thing is that you can still write everything in C# without needing to learn a new programming language.

What is Kotlin?

If you want to write a mobile app without using a framework on top or with just one platform like Android, you can develop it in Kotlin. (Kotlin has been a preferred language for Android app developers since 2019 when it became more popular when Java.) Kotlin targets Java Virtual Machine (JVM), compiles to JavaScript or Native code, and is supported in Spring Framework. It can be used to develop backend or web applications and to write in more concise manner compared to Java.

Querying data with LINQ

Most of the time when developing, we process some data to get the result we need. When processing data in C#, it is very useful to use Language Integrated Query (LINQ). LINQ queries data in a code similarly to how it’s done in a database. LINQ has two syntaxes: a query syntax that looks similar to SQL and a method syntax. In compile time, the query syntax translates into method calls for the .NET Common Language Runtime (CLR). (Some functions like Max and Count do not exist in query syntax.) I will share how to use LINQ’s method syntax to analyze coding when writing C# and how it relates to Kotlin.

When learning how LINQ works, you’ll find out about extension functions that help you write functions for a class without having direct access to it. Using the tactic appears as though you are calling methods from a class. However, it really exists in a different namespace. Extension functions help reduce the abstract helper or utilities classes to focus on the objects you are working with. In LINQ, those extension functions are implemented for IEnumerable and IQueryable

Let’s go over useful extension functions for both languages.

Selection

Getting all collection items into a certain format means selecting (i.e., Select, C#) or mapping (i.e., map, Kotlin) them. As a parameter, you should pass a function that transforms one collection item to the desired format.

For example, if there’s an array of people with their names and birth dates, you can create an array of people with their names and ages (instead of birth dates).

Here’s how the array looks in C#:

var persons = personsFromDatabase.Select(person => new Person
{
    Name = person.Name,
    Age = CalculateAge(person.BirthDate)
});

Here’s how the array looks in Kotlin:

val persons = personsFromDatabase.map{ Person(it.name, calculateAge(it.birthDate)) }

Two notable differences in addition to different name functions are that:

  • In Kotlin, you don’t have to explicitly define how the item inside of the collection should be called (e.g., person in C#). You can just use it.
  • Each time you pass a function to Kotlin, it is passed inside of curly brackets. In Kotlin, the keyword new is not needed and neither are semicolons.

Another case is when there is a two-layered collection, and you want to create one layer. C# uses SelectMany, whereas Kotlin uses flatMap or flatten. Kotlin’s flatMap works the same as C#’s SelectMany. The transformation function is passed as a parameter and one layer collection is returned. A transformation function is needed to get the collection from an element (e.g. when a property of an element is a collection). By comparison, flatten does not need a transformation function as it assumes that each element is an array or a collection itself.

Here’s an example:

val deepArray = arrayOf(
    arrayOf(1),
    arrayOf(2, 3),
    arrayOf(4, 5, 6)
)
println(deepArray.flatten()) // [1, 2, 3, 4, 5, 6]

deepArray is an array of arrays. After flatten, it becomes one single array. The same is true for lists. In other words, it should be used when the item inside of the collection is the collection itself. Regarding the syntax, Kotlin has val and var, which is the same as C# var. The difference between val and var in Kotlin is that val marks an immutable variable, while var means a mutable one.

Filtering

In some cases, you only need to access some data by applying filters.

C# uses Where and Kotlin uses filter. For example, if you want to select all the employees with the name Simona.

Here’s how the filter looks in C#:

employees.Where(employee => employee.Name == "Simona");

Here’s how the filter looks in Kotlin:

employees.filter {it.name == "Simona"}

Sorting

You can easily sort arrays of value type in both languages.

Here’s how to sort in C#:

Array.Sort(numbers);

This should work as well if the object class implements the IComparable interface.

Here’s how to sort in Kotlin:

numbers.sort()

For this to work in Kotlin, a Comparable interface needs to be implemented.

Both languages sort inside the array itself and don’t return anything.

In order to sort by property, C# uses OrderBy (ascending order) or OrderByDescending followed by ThenBy or ThenByDescending in order to sort several columns. The primary array does not change and provides a new sorted array.

Kotlin offers a variety of options for sorting by property.

  • Need to sort inside an array? Use functions with sort. If you want it a return sorted array, use sorted.
  • Need to sort by one property? Use the suffix By combined with either sort or sorted (i.e., sortBy and sortedBy).
  • Need to sort in descending order? Use the suffix Descending at the end as noted in the code below to return a new sorted array of persons sorted by age in descending order (from oldest to youngest).
persons.sortByDescending{ it.age }

Need to sort by multiple properties? Here’s where things get interesting. You’ll need a comparator, which can be added by using compareBy paired with the suffix With instead of By in the function name.

persons.sortedWith(compareBy({ it.age }, { it.name }))

Inside compareBy, you can add all the columns you want to sort by. If you want all of the columns to be sorted in descending order, use compareByDescending. However, if there's one column that needs descending order (and other ascending), you can add '-' before the property as noted here:

persons.sortedWith(compareBy({ it.name }, { - it.age }))

Compared to C#, Kotlin gives you more control on where and how sorting should happen, which can be useful sometimes. Keep in mind that very similar rules for constructing function names apply to other functions in Kotlin.

Quantifiers

Sometimes you need to ensure that a number of collection elements are proper. To check that All, Any and Contains can be used in C#.

The same options exist in Kotlin using lowercase (because of Kotlin code style), along with none and containsAll.

The following lines all mean the same thing, although one with none is easier to read:

tickets.none{ it.valid }
!tickets.any{ it.valid }
tickets.all{ !it.valid }

Instead of going through a second array and checking if each element exists in the first one (first line), you can just call containsAll (second line):

requiredRoles.all{personRoles.contains(it)}
personRoles.containsAll(requiredRoles)

Another synonym you can use for contains in Kotlin (if you want to check if one item is inside of an array) is:

if (item in array) {
  // do something to item
}

Generating arrays

When generating an array, you may want to have the same value applied across the array.

Here’s how to generate an array in C#:

Enumerable.Repeat(“Hello”, 5)

Here’s how generating that translates to Kotlin:

Array(5, {“Hello”})

When the end result is a range of numbers, C# uses the function:

Enumerable.Range(1, 5),

This in Kotlin translates to

1..5

If you want to create a countdown, use:

5 downTo 1

Use the below code for a more customized array:

1 .. 25 step 5 .

You can also run calculations while taking into account index of array using:

IntArray(5, {index -> index*2+5}).

Partitioning

C# and Kotlin differ in wording for partitioning, which makes figuring out which function’s the best to call somewhat difficult.

C# uses Skip, SkipWhile, Take, and TakeWhile. If you want to access elements from the beginning of an array, use Take and select a specific amount or choose what you need to take by adding a function as a parameter for TakeWhile. Alternatively, you can go toward the end using Skip, which allows you to ignore the first items, taking what is left, or similarly to TakeWhile there is SkipWhile which takes as a parameter a function that decides when to stop ignoring elements. If you want to get something from the middle, use the combination of Skip(5).Take(3);.

Kotlin can explicitly say how many elements you want from either the beginning or the end using take and takeLast. Instead of C#’s Skip, use drop which lets you decide whether you want to choose elements from the beginning or the end with dropLast. Just like C#, you can include the While suffix to choose by function. But that’s not all! You don’t have to combine the two functions to select something from the middle by using:

users.slide(1..3)

You can split data into two parts by predictable function with partition. If the predictable function returns true, the item goes to the first list. Otherwise, it goes to the second. The result of this is two new lists. 

users.partition (good, bad) = {it.good}

Aggregation

Have you wondered how using C# to find which object in an array has the maximum property? There is not a simple function inside System.Linq namespace. However, Kotlin does have functions maxBy or minBy (if a minimum property is needed) which returns the whole object.  

val object = objects.maxBy{it.Amount}

The quickest way that I found in C# to write the same is: ​

objects.Aggregate((maximum, next) => next.Amount > maximum.Amount ? next : maximum)

In the case shown above, this function takes in the accumulation function, which includes the accumulated value and the next value of the array as parameters. Inside the accumulation function, you can concatenate words, find bigger, smaller, or whatever you need, but you have to return the accumulated value to the current step. The accumulated function is called for each item in the array. You can start with the seed (in this case, the seed is 0).

objects.Aggregate(0, (sum, next) => return sum + next)

You can also add a final transformation function to access the name of the oldest person.

persons.Aggregate(firstPerson, (oldest, next) => next.Age > oldest.Age ? next : oldest, oldest => oldest.Name)

Kotlin has two similar functions: fold and reduce. If there is no need for seed, reduce can be used (then it’s the same as Aggregate first described version), otherwise use fold, which goes with the initial value for the accumulation.

Execution

In C#, LINQ methods are either executed immediately (if the result has a single value, non-enumerable, for example, using returned by Max, Average) or postponed until its result is used (also called deferred execution).

Deferred executions are dividable into two more categories: streaming and non-streaming.

  • Streaming operators read data one by one and return by one value. It can return results even if it has not read until the end of data.
  • Non-streaming reads all the data, processes it, and returns all at once. An example of a non-streaming operator would be sorting or grouping.

In Kotlin, by default, it processes the whole data before returning. It also has the option to go through data one by one, which can be useful when several operations are chained, and you don’t need all elements at the end. For that, you could add a “asSequence()” function before all other operations.

users.asSequence()
    .filter {it.name == “Simona”}
    .map { it.surname }
    .take(3)

In this case, it would stop as soon as it has three surnames shown in the result, without going further into the user array.

In conclusion

While learning a new language can be frustrating, I hope this guide helps you get to know C# and Kotlin. As described, Kotlin has a lot of variations of each function and allows developers to decide which option they find appropriate based on the situation. What would you want that C# offers by default? MaxBy or MinBy? No matter which language you choose, it is possible to write similar ideas that translate from one type of code to another. Remember, transferring your knowledge of C# to Kotlin or vice versa can be incredibly useful and a great way to learn another programming language fast.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK