Comments 97
интересно мнение по поводу этого языка как Java-программистов, так и C#. Стали бы Вы использовать Kotlin в своих проектах?
Почему бы и нет? Я android-разработчик, и особенно в свете недоступности полноценной java 8 для разработки под android, kotlin может быть как глоток воды в пустыне. Другое дело, что времени особо нету играться, а сразу в боевой проект тащить страшно.
Во всяком случае, в свете слухов о возможном использовании swift на андроиде, кажется мне, что лучше бы это был котлин.
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[MethodImpl(MethodImplOptions.NoInlining)]
[SecurityCritical]
public unsafe bool OpenMemoryMap(long memoryMapCapacity, out bool capacityIsSufficient)
{
bool lockTaken = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
this.CheckDisposed();
if (memoryMapCapacity <= 0)
{
throw new ArgumentOutOfRangeException("memoryMapCapacity", StringResources.MemoryMapCapacityOutOfRange);
}
bool result = false;
Monitor.TryEnter(this.stateSyncRoot, ObjectStateTimeout, ref lockTaken);
if (!lockTaken)
{
// some code
}
else
{
// some other code
}
return result;
}
catch (Exception exception)
{
Logger.Error(Helper.GetString(StringResources.UnableToAcquireViewHandlePointerBecauseException, this.name, exception));
return false;
}
finally
{
if (lockTaken)
{
Monitor.Exit(this.stateSyncRoot);
}
}
}
P.S. Выход по таймауту в оригинале перехватывается отдельно, я укоротил немного.
объясните, где я прокололся
Например, там, где сказали, что LINQ создает отдельный рабочий поток. Или там, где сказали, что async/await кидает выполнение метода в фоновый поток.
А разве LINQ не создает отдельный поток при работе?
Ни одна виденная мной реализация так не делала. Зачем?
A async/await передает код на выполнение в поток, который берется из пула потоков?
async-await вообще не управляет тем, где будет выполняться код.
нтересное делает компилятор и код, который он генерит, запускает задачу в потоке и ждет
А вот и нет. Код, который он генерит, всего лишь создает continuation (в том случае, когда задача еще не выполнилась, иначе просто идет выполнение дальше).
А это подхватывает уже другой поток
С чего вы это взяли? «Подхватывает» continuation тот поток, который выбирается шедулером.
(а запоминание контекста синхронизации — это не «дополнительные возможности await», банальный ContinueWith это умеет)
(а вот от сохранения контекста зависит только то, где будет выполняться continuation).
очень странно то что вы говорите, я когда то делал тесты, небольшие объекты с коротким временем жизни работали процентов на 10% быстрей «ручного управления памятью», новосозданный объект создается в поколении 0, которое всегда находится в кеше процессора и работает с максимально возможной скоростью, объекты с коротким временем жизни очень быстро удаляются из памяти, GC пробегает только по «живым» объектам. Да важно что бы объекты не «бегали» между нативным кодом и управляемым, это уложняет работу GC и вообще много ресурсов тратится на таких переходах.
Можете описать что делает ваш проект и почему он должен держать такой объем поступающих данных?
Специфики не знаю, может ошибаюсь, но когда все идут по пути упрощения всего и вся вы создаете комбайн с привязками к платформе, с которым потом никто не сможет ничего сделать. Экономите на серверах?
if (*((bool*)(internalDataStorage + 3792)))
{
Interlocked.Add(ref totalStringLength, -*((int*)(internalDataStorage + 3796)));
}
#if TRACE
Logger.Trace("Report::set_ReceivingServerIdField()");
#endif
((IComponentInternal)this).SetDirty();
Thread.MemoryBarrier();
allOk = true;
Это С#, ага.
А есть что-то по сути сказать, аргументированно?
Функции также могут быть вызваны при помощи инфиксной нотации
В стандартной библиотеке инфиксные функции есть? Примеры? А то прикольно, но не очень понятно, зачем. :)
С каррированием такая же петрушка: всё время говорят, как это круто, а в примерах неизменно "SampleFunction" с "a + b + c"...
Подходы у языков одинаковые, только в Kotlin это делать удобнее за счет более компактного синтаксиса.
Только в шарпе дженерики, а в котлине инты… Можете эквивалентный код показать?
Чтобы заставить компилятор это сделать, необходимо добавить в объявлении метода модификатор inline
Компилятор сам не догадается? Старнно видеть подобные подсказки компилятору в современном высокоуровневом языке аж на уровне языка.
Обычно, инлайнинг реализуют не на уровне компилятора, а на уровне бэкэнда (HotSpot, LLVM, Crankshaft), которые оперируют более простыми сущностями (SSA, PDG). В Kotlin инлайнинг — это не особенность рантайма, это семантическая особенность. Например, т.к. inline-лямбда гарантированно инлайнится, ей становится доступен поток управления функции, откуда её вызывают. Это нужно вот для чего. Есть у нас языковая контрукция:
for (i in 1..100) {
// do something
}
Теперь мы хотим сделать свою ФВП each и вызывать её так:
(1..100).each { i ->
// do something
}
Проблема в том, что конструкции в случае с Java/JavaScript/C# являются неравнозначными, ибо в первом случае можно делать break/continue/return, а во втором — нельзя. Так вот в Kotlin можно делать как минимум return, т.е. return не из самой лямбды, а из объемлющей именованной функции (а в будущем, надеюсь, добавят поддержку break/continue). Собственно, inline это и означает — встроить код в поток управления вызывающей функции.
Кстати, на практике VM умеют хорошо инлайнить только мономорфные вызовы, а лямбду переданную, пусть даже в мономорфную ФПВ, заинлайнить уже достаточно проблематично. Так что пока без подсказок компилятору тут никак.
Хм. Прелюбопытно. Этакий мини-макрос получается. Действительно, доступа к управляющим инструкциям из лямбд в подобных случаях, бывает, не хватает.
Но, по-моему, это усложняет понимание кода: непонятно, куда выкинет return — приходится знать, инлайновый вызов или нет.
В стандартной библиотеке инфиксные функции есть? Примеры? А то прикольно, но не очень понятно, зачем. :)
Битовые операции в Котлине реализованы в виде инфиксных функций or/and/xor
С каррированием такая же петрушка: всё время говорят, как это круто, а в примерах неизменно «SampleFunction» с «a + b + c»…
Например, функцию sum в функциональных языках часто реализуют через карринг функции fold. Т.е.
sum = foldl 0 (+)
Правда, это не очень относится к Kotlin, т.к. это не чисто функциональный язык.
Битовые операции в Котлине реализованы в виде инфиксных функций or/and/xor
Как приоритеты разруливаются?
К сожалению (а может, и к счастью), тут нельзя, как в некоторых языках, явно задать приоритет инфиксной функции.
Ха-ха, инфиксные функции в приоритетах находятся аккуратно на месте битовых операторов в C++. :)) То есть смешать and и or без скобок нормально не получится (впрочем, многие ставят скобки в любом случае), но относительно других операций приоритет привычный. Приоритет будто специально подобрали для битовых операций. :)
Битовые операции в Котлине реализованы в виде инфиксных функций or/and/xor
Как же я от этого страдал когда нужно было понавертеть много битовых вычислений.
Вот вы его часто упоминаете. Не знакомы со Streams API из Java 8?
Зачем писать 4 функции, когда можно написать одну?
fun f(i: Int = 1, j: Int = 2, k: Int = 3) = i + j + k
вместо
fun sampleFunc(a: Int, b: Int, c: Int): Int {
return a + b + c
}
fun f3(a: Int, b: Int): Int {
return sampleFunc(a, b, 3)
}
fun f2(a: Int): Int {
return f1(a, 2)
}
fun f1(): Int {
return f2(1)
}
Результат:
fun main(args: Array<String>) {
println(f()) //6
println(f(2)) //7
println(f(2, 2)) //7
}
Представляют интерес Data Classes. Данные классы используются для хранения данных и больше ничего не делают.
На самом деле, для этого не надо никаких data class. Например, вот такой класс:
class A(var u: Int, var v: String, var w: Boolean)
На самом деле, есть такое понятие как value object (лучше почитать DDD Эванса), и вот, мне кажется, что data class — это отличный способ реализовать данный паттерн. На каждом углу кричат, что value object должны быть immutable, и я с этим мнением вполне согласен (не хочу приводить целую пачку аргументов здесь, кому надо — гуглите по ключевым словам value object immutable). Так вот, отсюда вытекает, что
1. Если уж не запрещать var в декларации data class, то хотя бы надо выдавать предупреждение, включённое в настройках intentions по-умолчанию
2. В документации к языку и официальных блог-постах тщательно объяснять этот момент.
3. Отписываться в комментах к статьям вроде этой, которые, о ужас, предлагают объявлять entity как data class.
Я уже поднимал эту тему, но мне, к сожалению, сказали, что мой подход чрезмерно религиозен. Ну по крайней мере, буду сам стараться и просвещать по мере сил.
С практической точки зрения переопределение equals/hashCode, которые нестабильны (т.е. изменяются со временем жизни объекта) может привести к поломке HashSet/HashMap. Да и контракт hashCode явно требует его стабильности. Зависимость hashCode от состояния объекта (т.е. от поля, объявленного как var) как раз делает hashCode нестабильным.
Да, стал бы. По опыту, я вижу большие перспективы у подхода «одна VM — много языков» или даже Язык++ с удобным сахаром транспилируемым в просто Язык. Самым ярким примером для меня стал TypeScript, который позволял использовать плюшки ES2015 еще в 2013-ом году на продакшене, не говоря уже о его собственных плюшках. Потом появился Roslyn, сделав C# раширяемым (хотя тут главное не переборщить). Для банковской сферы, где новый код должен быть совместим со старым без вариантов, это пока единственный жизнеспособный подход что я видел чтоб не застревать на старых версиях языков годами.
Совершенно не понятно зачем на VM тащить мусор вроде inline. Это сугубо работа компилятора и нечего лезть к нему со своими указами. Если нужно выжимать максимум, для этого есть куда более подходящие языки программирования.
тут
Про «парсить» вообще смешно — ЯП нужны чтобы ЛЮДЯМ было удобно писать, а главное ЧИТАТЬ.
(это же старый спор про implicit typing vs explicit typing)
Вы же меня завуалировано оскорбляете и пытаетесь доказать что я не прав.
И да, если бы я в своем примере заменил слово «строка» на некий класс и расписал его на паре страниц кода — то вы бы не стали завуалировано меня оскорблять?
Я здесь ни с кем не спорил, не призывал, не отстаивал свою точку зрения, а только высказал свое мнение в нейтральной форме.
Вот и я высказываю свое мнение — пусть и в форме вопроса.
Вы же меня завуалировано оскорбляете
О нет, ни капли.
пытаетесь доказать что я не прав.
Нет, я пытаюсь понять, зачем вам нужно то, что вы считаете вам более удобным. Это вообще полезно иногда, причем для обеих сторон.
Давайте представим себе сценку:
я разработчик, ко мне приходит заказчик, и говорит: «нарисуй мне 7 красных линий», а я ему в ответ: «мне не хочется разбирать головоломные синтаксисы, давай я нарисую 7 синих — мне так проще».
И что сделает заказчик? Он найдет того кто нарисует ему красные линии, потому что ему нужны красные, ему так удобно, ему просто так хочется в конце концов и его не волнует (и НЕ ДОЛЖНО волновать) то с какими трудностями сталкивается разработчик. И объяснять разработчику почему именно красных и именно 7 — он не обязан, и искать компромиссное решение (7 фиолетовых линий) тоже не обязан.
А нечитаемым можно сделать абсолютно любой язык (взять, например, тот же «падонкафский» русский), так что давайте не будем об этом.
fun f2(a: Int): Int {
return f1(a, 2)
}
fun f1(): Int {
return f2(1)
}
если не ошибаюсь, f2 должна возвращать f3, а не f1
Что-то и время комплиции и поддержка IDE до сих пор в котлине хромает.
На jpoint и jet будут доклады от Дмитрия Жемерова про производительность Kotlin с JMH бенчмарками, рекомендую.
Краткий обзор Kotlin и сравнение с C#