[Java, .NET, Разработка мобильных приложений, C#, Kotlin] C# vs Kotlin
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Когда речь заходит о сахаре и модных фичах в языках программирования, среди первых вариантов на ум приходят C# и Kotlin. Поскольку эти два языка занимают схожие ниши, то есть, строго типизированы, обладают сборкой мусора, кроссплатформенны, применяются как на бекенде, так и в мобильной разработке, то сегодня мы попытаемся сравнить их синтаксические возможности и устроить небольшое голосование. Чтобы сравнение прошло честно, будем рассматривать последние версии обоих языков. Оговорюсь о своей непредвзятости: мне одинаково нравятся оба языка, они находятся в непрерывном развитии и не отстают друг от друга. Эта статья является сравнительной, а не обучающей, поэтому некоторые заурядные синтаксические возможности могут быть опущены.Начнем с точки входаВ C# эту роль играет статический метод Main или top-level entry point, например
using static System.Console;
WriteLine("Ok");
В Kotlin нужна функция main
fun main() = println("Ok")
По этим небольшим двум примерам в первую очередь заметно, что в Kotlin можно опускать точку с запятой. При более глубоком анализе видим, что в C#, несмотря на лаконичность показательного entry point, статические методы в остальных файлах по прежнему требуется оборачивать в класс и явно импортировать из него (using static System.Console), а Kotlin идет дальше и разрешает создавать полноценные функции. Обьявление переменныхВ C# тип пишется слева, а для создания экземпляра используется ключевое слово new. В наличии есть специальное слово var, которым можно заменить имя типа слева. При этом переменные внутри методов в C# остаются подвержены повторному присваиванию.
Point y = new Point(0, 0);
var x = new Point(1, 2);
x = y; // Нормально
В Kotlin типы пишутся справа, однако их можно опускать. Помимо var, доступен и val который не допускает повторного присваивания. При создании экземляров не нужно указывать new.
val y: Point = Point(0, 0)
val x = Point(1, 2)
x = y // Ошибка компиляции!
Работа с памятьюВ C# нам доступны значимые (обычно размещаются на стеке) и ссылочные (обычно размещаются в куче) типы. Такая возможность позволяет применять низкоуровневые оптимизации и сокращать расход оперативной памяти. Для объектов структур и классов оператор '==' будет вести себя по разному, сравнивая значения или ссылки, впрочем это поведение можно изменить благодаря перегрузке. При этом на структуры накладываются некоторые ограничения связанные с наследованием.
struct ValueType {} // структура, экземпляры попадут на стек
class ReferenceType {} // ссылочный тип, экземпляры будут в куче
Что до Kotlin, то у него нет никакого разделения по работе с памятью. Сравнение '==' всегда происходит по значению, для сравнения по ссылке есть отдельный оператор '==='. Объекты практически всегда размещаются в куче, и только для некоторых базовых типов, например Int, Char, Double, компилятор может применить оптизмизации сделав их примитивами jvm и разместив на стеке, что никак не отражается на их семантике в синтаксисе. Складывается впечатление что рантайм и работа с памятью это более сильная сторона .NET в целом.Null safetyВ C# (начиная с 8ой версии) есть защита от null. Однако ее можно явно обойти с помощью оператора !
var legalValue = maybeNull!;
// если legalValue теперь null,
// то мы получим exception при первой попытке использования
В Kotlin для использования null нужно использовать два восклицания, но есть и другое отличие
val legalValue = maybeNull!!
// если maybeNull == null,
// то мы получим exception сразу же
Свойства классовВ C# доступна удобная абстракция вместо методов get/set, то есть всем известные свойства. При этом традиционные поля остаются доступны.
class Example
{
// Вычислено заранее и сохранено в backing field
public string Name1 { get; set; } = "Pre-calculated expression";
// Вычисляется при каждом обращении
public string Name2 => "Calculated now";
// Традиционное поле
private const string Name3 = "Field";
}
В Kotlin полей нет вообще, по умолчанию доступны только свойства. При этом в отличие от C# public это область видимости по умолчанию, поэтому это ключевое слово рекомендукется опускать. Для разницы между свойствами, допускающими set и без него, используются все те же ключевые var/val
class Example {
// Вычислено заранее и сохранено в backing field
val name1 = "Pre-calculated expression"
// Вычисляется при каждом обращении
val name2 get() = "Calculated now"
}
Классы данныхВ C# достаточно слова record чтобы создать класс для хранения данных, он будет обладать семантикой значимых типов в сравнении, однако по прежнему остается ссылочным (будет размещаться в куче):
class JustClass
{
public string FirstName { init; get; }
public string LastName { init; get; }
}
record Person(string FirstName, string LastName);
...
Person person1 = new("Nancy", "Davolio");
Person person2 = person1 with { FirstName = "John" };
В Kotlin нужно дописать ключевое слово data к слову class
class JustClass(val firstName: String, val lastName: String)
data class Person(val firstName: String, val lastName: String)
...
val person1 = Person("Nancy", "Davolio")
val person2 = person1.copy(firstName = "John")
Расширения типовВ C# такие типы должны находиться в отдельном статическом классе и принимать вызывающий первым аргументом, помеченным this
static class StringExt
{
public static Println(this string s) => System.Console.WriteLine(s)
public static Double(this string s) => s + s
}
В Kotlin расширямый тип должен находиться слева от метода, который можно разместить в любом месте. При этом расширить тип можно не только методом, но и свойством
fun String.println() = println(this)
fun String.double get() = this * 2
Лямбда выраженияВ C# для них есть специальный оператор =>
numbers.Any(e => e % 2 == 0);
numbers.Any(e =>
{
// объемная логика ...
return calculatedResult;
})
В Kotlin лямбды органично вписываются в Си-подобный синтаксис, кроме того во многих случаях компилятор заинлайнит их вызовы прямо в используемый метод. Это позволяет создавать эффективные и красивые DSL (Gradle + Kotlin например).
numbers.any { it % 2 == 0 }
numbers.any {
// объемная логика ...
return calculatedResult
}
Условия и шаблоныУ C# есть очень мощный pattern matching c условиями (пример из документации)
static Point Transform(Point point) => point switch
{
{ X: 0, Y: 0 } => new Point(0, 0),
{ X: var x, Y: var y } when x < y => new Point(x + y, y),
{ X: var x, Y: var y } when x > y => new Point(x - y, y),
{ X: var x, Y: var y } => new Point(2 * x, 2 * y),
};
У Kotlin есть аналогичное switch выражение when, которое, несмотря на наличие возможности сопоставления с образцом, не может одновременно содержать деконструкции и охранных условий, но благодаря лаконичному синтаксису можно выкрутиться:
fun transform(p: Point) = when(p) {
Point(0, 0) -> Point(0, 0)
else -> when {
x > y -> Point(...)
x < y -> Point(...)
else -> Point(...)
}
}
// или так
fun transform(p: Point) = when {
p == Point(0, 0) -> Point(0, 0)
p.x < y -> Point(p.x + y, p.y)
p.x > y -> Point(p.x - p.y, p.y)
else -> Point(2 * p.x, 2 * p.y)
}
Подводя итоги Уложить в одной статье все отличия обоих языков практически нереально. Однако кое какие выводы сделать уже можем. Заметно что Kotlin-way скорее в том чтобы минимизировать количество ключевых слов, реализуя весь сахар поверх базового синтаксиса, а C# стремится стать более удобным увеличивая количество доступных выражений на уровне самого языка. У Kotlin преимущество в том что его создатели могли оглядываться на удачные фичи C# и лаконизировать их, а C# выигрывает за счет мощной поддержки в лице Microsoft и лучшего рантайма.
===========
Источник:
habr.com
===========
Похожие новости:
- [Java] JDK 17: новые функции в Java 17 (перевод)
- [JavaScript] Конец вечного противостояния snake_keys VS camelKeys: наводим порядок в стилях написания переменных
- [Разработка мобильных приложений, Тестирование мобильных приложений, Аналитика мобильных приложений, Мозг, Здоровье] Cognitive therapy и мобильные приложения против невротической депрессии
- [Программирование, Angular] Простая архитектура приложений на фреймворке Angular (перевод)
- [Тестирование веб-сервисов] Зачем нам нужно автоматизированное тестирование? (перевод)
- [JavaScript, Видеоконференцсвязь] Видеоконференции — как бороться с высокой загрузкой ЦПУ?
- [Разработка мобильных приложений, Обработка изображений, Машинное обучение, Искусственный интеллект] Ученые компании Smart Engines окончательно решили задачу распознавания паспорта РФ
- [Программирование, Искусственный интеллект, IT-компании] Microsoft разработала ИИ-систему, преобразующую простые текстовые запросы в код
- [Java, Разработка под Android] Инициализация Rx цепочки
- [Веб-дизайн, JavaScript, jQuery, HTML] EasyUI: действительно easy?
Теги для поиска: #_java, #_.net, #_razrabotka_mobilnyh_prilozhenij (Разработка мобильных приложений), #_c#, #_kotlin, #_kotlin_vs_c#, #_c#_vs_kotlin, #_.net, #_java, #_c#, #_kotlin, #_jvm, #_microsoft, #_java, #_.net, #_razrabotka_mobilnyh_prilozhenij (
Разработка мобильных приложений
), #_c#, #_kotlin
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:36
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Когда речь заходит о сахаре и модных фичах в языках программирования, среди первых вариантов на ум приходят C# и Kotlin. Поскольку эти два языка занимают схожие ниши, то есть, строго типизированы, обладают сборкой мусора, кроссплатформенны, применяются как на бекенде, так и в мобильной разработке, то сегодня мы попытаемся сравнить их синтаксические возможности и устроить небольшое голосование. Чтобы сравнение прошло честно, будем рассматривать последние версии обоих языков. Оговорюсь о своей непредвзятости: мне одинаково нравятся оба языка, они находятся в непрерывном развитии и не отстают друг от друга. Эта статья является сравнительной, а не обучающей, поэтому некоторые заурядные синтаксические возможности могут быть опущены.Начнем с точки входаВ C# эту роль играет статический метод Main или top-level entry point, например using static System.Console;
WriteLine("Ok"); fun main() = println("Ok")
Point y = new Point(0, 0);
var x = new Point(1, 2); x = y; // Нормально val y: Point = Point(0, 0)
val x = Point(1, 2) x = y // Ошибка компиляции! struct ValueType {} // структура, экземпляры попадут на стек
class ReferenceType {} // ссылочный тип, экземпляры будут в куче var legalValue = maybeNull!;
// если legalValue теперь null, // то мы получим exception при первой попытке использования val legalValue = maybeNull!!
// если maybeNull == null, // то мы получим exception сразу же class Example
{ // Вычислено заранее и сохранено в backing field public string Name1 { get; set; } = "Pre-calculated expression"; // Вычисляется при каждом обращении public string Name2 => "Calculated now"; // Традиционное поле private const string Name3 = "Field"; } class Example {
// Вычислено заранее и сохранено в backing field val name1 = "Pre-calculated expression" // Вычисляется при каждом обращении val name2 get() = "Calculated now" } class JustClass
{ public string FirstName { init; get; } public string LastName { init; get; } } record Person(string FirstName, string LastName); ... Person person1 = new("Nancy", "Davolio"); Person person2 = person1 with { FirstName = "John" }; class JustClass(val firstName: String, val lastName: String)
data class Person(val firstName: String, val lastName: String) ... val person1 = Person("Nancy", "Davolio") val person2 = person1.copy(firstName = "John") static class StringExt
{ public static Println(this string s) => System.Console.WriteLine(s) public static Double(this string s) => s + s } fun String.println() = println(this)
fun String.double get() = this * 2 numbers.Any(e => e % 2 == 0);
numbers.Any(e => { // объемная логика ... return calculatedResult; }) numbers.any { it % 2 == 0 }
numbers.any { // объемная логика ... return calculatedResult } static Point Transform(Point point) => point switch
{ { X: 0, Y: 0 } => new Point(0, 0), { X: var x, Y: var y } when x < y => new Point(x + y, y), { X: var x, Y: var y } when x > y => new Point(x - y, y), { X: var x, Y: var y } => new Point(2 * x, 2 * y), }; fun transform(p: Point) = when(p) {
Point(0, 0) -> Point(0, 0) else -> when { x > y -> Point(...) x < y -> Point(...) else -> Point(...) } } // или так fun transform(p: Point) = when { p == Point(0, 0) -> Point(0, 0) p.x < y -> Point(p.x + y, p.y) p.x > y -> Point(p.x - p.y, p.y) else -> Point(2 * p.x, 2 * p.y) } =========== Источник: habr.com =========== Похожие новости:
Разработка мобильных приложений ), #_c#, #_kotlin |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:36
Часовой пояс: UTC + 5