Pull to refresh

Comments 97

интересно мнение по поводу этого языка как Java-программистов, так и C#. Стали бы Вы использовать Kotlin в своих проектах?

Почему бы и нет? Я android-разработчик, и особенно в свете недоступности полноценной java 8 для разработки под android, kotlin может быть как глоток воды в пустыне. Другое дело, что времени особо нету играться, а сразу в боевой проект тащить страшно.
Во всяком случае, в свете слухов о возможном использовании swift на андроиде, кажется мне, что лучше бы это был котлин.

Насколько я знаю, есть плагин, который портирует код с Java на Kotlin.
Kotlin-плагин под Intellij IDEA (и под Android Studio, соответственно) и содержит эту функциональность.
Java8 же обещали быть с Android N. Свифт, думаю, не угрожает яве, т.к. одно дело запустить «хеллоу ворлд» на нем на андроиде, другое — забайндить всё Андроид СДК.
Java8 же обещали быть с Android N

Только работать все будет только на том же N. Бекпорт только пока для лямбд вроде обещали, а их и сейчас можно при желании ретролямбдой получить.

Вы бы статью переименовали что ли. А то название как-то мало соответствует содержанию.
Например, написать, что это сравнение языков Kotlin и C#?
UFO just landed and posted this here
У меня всегда двоякое впечатление от описания всяческого «удобного» синтаксического сахара. Мой C# после всех оптимизаций и фиксов вырос в безумный набор unsafe/fixed/CER/interlocked/methodimpl вуду, аж goto в двух местах есть. И мне сознательно пришлось отказаться от linq, foreach и т.д. почти везде. И когда я читаю производительный код на Java там та же картина. Вобщем без бенчмарков сравнение не катит. А ключевым моментом при выборе .NET/Java для меня был рантайм, AppDomain и все такое. У меня можно почти все и на VB портировать, сомневаюсь что что-то изменится.
Это сравнение чисто с точки зрения синтаксиса. Производительность тут не затрагивалась. Мне было интересно рассматривать этот язык, потому что он похож на С#. А как заметил мой коллега по работе, производительный код всегда тяжело читать. И как я вижу, иногда жертвуют производительностью ради хорошей читаемости и сопровождения кода. Я думаю, что грамотное использование синтаксического сахара позволит сделать код более приятным. Тот же С# в последних версиях имеет сахар, которым занимается компилятор, а сама платформа не изменяется.
Ну обеспечение атомарности операций компилятор на себя не возьмет. Что, например, вот отсюда можно сахаром заменить:

        [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. Выход по таймауту в оригинале перехватывается отдельно, я укоротил немного.
Мм, интересно, что это у вас за проект такой)) Тут действительно, места ему нет, да и это может сказаться на работе кода. Однако, как я понимаю, это специфичный код. В большинстве случаев от сахара будет польза. К примеру работа с БД. Я как-то работал с MongoDB и там все обращения с выборкой и фильтрацией сделаны через LINQ, что очень удобно и быстро на самом деле. Если я захочу использовать, к примеру, SIMD-расширения в C#, то там код усложнится сразу, зато выше производительность. Или же еще взять то, что в Java в основном рекомендуется работать с интерфейсами, а не с конкретной реализацией, хотя такой подход дает нагрузку на JVM. Однако, на это особо не обращают внимания, так как такой подход позволяет писать удобный код.
Ну у меня в рабочем проекте MongoDB ГОРАЗДО медленнее PostgreSQL на записи json в базу. Конечно мы в PostgreSQL пишем бинарные данные и пакетами, но .NET MongoDB это просто шлак со всем своим LINQ. Т.е. в сотни раз медленнее, на потоке в 4 Гигабита json c 60000+ записей в секунду. Так что не знаю о чем вы.
Ну опять же, у Вас как я понимаю очень нагруженная система, соответственно специфические требования) В большинстве программ это удобно. Я вообще плюсы использую, когда мне нужна скорость, как у себя в проекте с математическими расчетами. Плюсы и быстрее и удобнее, хоть и требуют очень осторожного подхода) мелкие иногда ошибки, а память кушать начинает огромными темпами
Ну, давайте так. .NET у нас для надежности, как бы странно это ни звучало. Запуск плагинов в отдельных процессах и AppDomain, контроль лайфтайма объектов и т.д. Очень много бонусов по сравнению с нативным кодом по скорости разработки. Система нагружена из-за реалтаймового обновления всех этих данных, поэтому математическиме расчеты и рендер интерфейса на GPU, куча native кода и т.д. Почему я для ненагруженной системы должен использовать Mongo если Postgres лучше, я не знаю. Память мы частично вручную контролируем, т.к. при таких объемах данных в много потоков, процессов и приложений GC не справляется, но отказавшись от сахара мы снизили потребность в памяти во много раз. Структуры, массивы на стеке, прямой доступ к памяти, Dispose всего и вся очень быстро исправляют ситуацию. Прототип, единичные вызовы могут и должны использовать Linq и все такое, но в 90% случаев от этого приходится отказаться.
Тут с Вами согласен на все 100%. Тот же LINQ создает отдельно рабочий поток (без вашего ведома) и из последовательности делает выборку по определенному критерию (поэтому рекомендуется большие списки инициализировать в левой части). При этом имеет ленивую инициализацию, так что только дефолтные настройки уже не радуют. Затем тот же async/await, который компилятор за кулисами раскручивает до конечного автомата и создает дополнительные объекты для сохранения состояния метода и всех его переменных (а если у вас много локальных переменных в методе, это опять же память), а затем кидает выполнение асинхронного метода в фоновый поток (благо из пула берется), а потом ожидание выполнения с уведомлением через потоки ввода-вывода системы, число которых равно числу физических ядер процессора (Hyper-Thearing с его виртуальными ядрами не считается) — все это несомненно нагрузка на систему и приводит к постоянным аллокациям и нагрузкам на систему. А учитывая как .NET резервирует память, при помощи полигонов… То, что вы сейчас описали, несомненно нуждается в простых, но надежных методах без всякой «красивой» приблуды. Тут ему естественно делать нечего, поэтому я считаю, что необходимо знать чего стоит эта красота на самом деле. Поэтому часто сижу и читаю код, который генерит компилятор)))
Интересно, те кто минусуют, объясните, где я прокололся)
объясните, где я прокололся

Например, там, где сказали, что LINQ создает отдельный рабочий поток. Или там, где сказали, что async/await кидает выполнение метода в фоновый поток.
А разве LINQ не создает отдельный поток при работе? A async/await передает код на выполнение в поток, который берется из пула потоков?
А разве LINQ не создает отдельный поток при работе?

Ни одна виденная мной реализация так не делала. Зачем?

A async/await передает код на выполнение в поток, который берется из пула потоков?

async-await вообще не управляет тем, где будет выполняться код.
Сейчас нет у меня под рукой той книги, в которой читал про создание отдельного потока) Возможно, что-то путаю, я уточню. Насчет async/await да, это всего лишь синтаксис, самое интересное делает компилятор и код, который он генерит, запускает задачу в потоке и ждет Task или Task<_Result_>, которые выполняются в пуле потоков)
нтересное делает компилятор и код, который он генерит, запускает задачу в потоке и ждет

А вот и нет. Код, который он генерит, всего лишь создает continuation (в том случае, когда задача еще не выполнилась, иначе просто идет выполнение дальше).
Ну то есть как, происходит проверка на выполнение задачи. Если она не выполнилась, то происходит процедура подписки о завершении задачи Task. Также в процедуре подписки участвует объект AwaitUnsafeOnCompleted, который реализует дополнительные возможности await, в том числе запоминание контекста синхронизации, который нужно будет восстановить при возобновлении. Этот метод планирует конечный автомат для перехода к следующему действию.И вот он как раз занимается задачами… А это подхватывает уже другой поток
А это подхватывает уже другой поток

С чего вы это взяли? «Подхватывает» continuation тот поток, который выбирается шедулером.

(а запоминание контекста синхронизации — это не «дополнительные возможности await», банальный ContinueWith это умеет)
Ну, а планировщик разве не берет поток из пула потоков?
Совершенно не обязательно.
То есть как? Насколько я помню, Task всегда выполняется в подобного рода потоках? Или же зависит от того, сохранят контекст или нет?
Для начала — зависит от природы таска, если это IOCP, то поток вообще может быть один и тот же, в котором выполнение и шло (а может и не быть, здесь тоже как шедулеру виднее). А если таск вычислительный, и порожден явно, то просто зависит от шедулера.

(а вот от сохранения контекста зависит только то, где будет выполняться continuation).
Хмм, а во про природу тасков не знал. У Алекса Дэвиса этого не видел, когда читал его книгу про асинхронное программирование)) спасибо
Вот и гуру подтянулся.
> Память мы частично вручную контролируем,
очень странно то что вы говорите, я когда то делал тесты, небольшие объекты с коротким временем жизни работали процентов на 10% быстрей «ручного управления памятью», новосозданный объект создается в поколении 0, которое всегда находится в кеше процессора и работает с максимально возможной скоростью, объекты с коротким временем жизни очень быстро удаляются из памяти, GC пробегает только по «живым» объектам. Да важно что бы объекты не «бегали» между нативным кодом и управляемым, это уложняет работу GC и вообще много ресурсов тратится на таких переходах.
Приведу статистику live системы: 4 гигабита идет в shared memory между процессами, например, каждые 20 мс происходит обновление данных. Во время обновления на стеке создаются 5-6 двумерных массивов на 1000 элементов среди которых в основном структуры, но есть и инстансы классов, массивы нужны чтобы работать с отдельным снэпшотом данных в каждом из нескольких потоков обработки. Сами данные копируются из shared memory, немного конвертируются. Мержит снапшоты отдельный тред. Параллельно при вызове рендера из композишен таргет, в еще одном треде, последний снапшот копируется, обрабатывается и отправляется в видеопамять на рендер, чтобы на следующем вызове рендере обновить из текстуры интерфейс. Сам рендер естественно еще в двух тредах используя deferred context. И еще один тред готовит снапшоты для рендера, инкрементально накатывая диффы, чтобы не гонять снапшоты целиком. Чтобы все это работало без тормозов GC переводится в sustainedlowlatency чтобы не мешал, и приходится все кроме структур диспозить руками, т.к. там дочерта unmanaged ресурсов, присваивать указателям null насильно, т.к. для скорости часть переменных по возможности вынесены непосредственно из методов. Ну и все это по максимуму lock-free. Вот тут и пригождается все вплоть до unchecked, и большая часть данных гоняется в unmanaged через memmove и array.copy.
MongoDB создали не для того чтобы он быстрее PostgreSQL писал данные, а для того чтобы эти данные равномерно разливать по постоянно добавляющимся серверам, тем самым нивелируя все объемы и тут ему равных нет. В случае с PostgreSQL и их шардированием все это будет неповоротливо и жутко неудобно.
Можете описать что делает ваш проект и почему он должен держать такой объем поступающих данных?
Специфики не знаю, может ошибаюсь, но когда все идут по пути упрощения всего и вся вы создаете комбайн с привязками к платформе, с которым потом никто не сможет ничего сделать. Экономите на серверах?
Ну с такой разницей в производительности меня Citus полностью устраивает для шардинга PostgreSQL. Плюс мне вообще не надо high-accessibility, мне надо fast-writes. Я не могу сейчас привести сравнение производительности распределенных MongoDB и PostgreSQL т.к. не делал этого еще, но чувствую первая от второго недалеко оторвется. У нас специфический софт, торговая платформа, мы в угоду производительности и латентности жертвуем объемами памяти, иногда даже отключаем hyper-threading (да да). Ну и все решения принимались после недель профайлинга на разных конфигурациях и т.д.
И вы не поверите, в продакшен проектах 90% кода так написано, кроме некоторых тестов. Откройте исходники .NET, узнаете для себя много нового. Я неделю копался наверное после релиза.
Читал исходники SIMD-реализации в .NET, достаточно познавательно на самом деле.
А вот производительный код, который да, переоптимизирован немного, для сравнения:
                        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;

Это С#, ага.

Не извращайнесь, пишите на С++ :)

Да уже готовлюсь морально к портированию…
Отлично, в следующей статье сравните с JS или Python для порядка.
UFO just landed and posted this here

А есть что-то по сути сказать, аргументированно?

Не, даже и не ждите. По прошлым комментариям хорошо видно.
Показалось, что его ник знаком и да, действительно видел его уже в статье про БЭМ, где они поливал БЭМ помоями, но при этом не мог привести конкретных аргументов, а то, что ему по этой причине ожидаемо ставили минусы — называл заговором Яндекса(ну или как-то похоже)
Функции также могут быть вызваны при помощи инфиксной нотации

В стандартной библиотеке инфиксные функции есть? Примеры? А то прикольно, но не очень понятно, зачем. :)


С каррированием такая же петрушка: всё время говорят, как это круто, а в примерах неизменно "SampleFunction" с "a + b + c"...


Подходы у языков одинаковые, только в Kotlin это делать удобнее за счет более компактного синтаксиса.

Только в шарпе дженерики, а в котлине инты… Можете эквивалентный код показать?


Чтобы заставить компилятор это сделать, необходимо добавить в объявлении метода модификатор inline

Компилятор сам не догадается? Старнно видеть подобные подсказки компилятору в современном высокоуровневом языке аж на уровне языка.

UFO just landed and posted this here
> Компилятор сам не догадается? Старнно видеть подобные подсказки компилятору в современном высокоуровневом языке аж на уровне языка.

Обычно, инлайнинг реализуют не на уровне компилятора, а на уровне бэкэнда (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 — приходится знать, инлайновый вызов или нет.

UFO just landed and posted this here

Ещё и метки замысловатые… return@forEach — это весело. :)


Теперь принцип работы понятен, но всё-таки хотелось бы узнать о практическом применении: возникают ли проблемы с тем, что приходится запоминать, где лямбды инлайновые, а где нет, например.

UFO just landed and posted this here
Касательно замечания по break/continue/return. Continue можно реализовать с помощью фильтрации набора, еще до самой итерации. Break можно реализовать по средствам return.
В стандартной библиотеке инфиксные функции есть? Примеры? А то прикольно, но не очень понятно, зачем. :)

Битовые операции в Котлине реализованы в виде инфиксных функций or/and/xor

С каррированием такая же петрушка: всё время говорят, как это круто, а в примерах неизменно «SampleFunction» с «a + b + c»…

Например, функцию sum в функциональных языках часто реализуют через карринг функции fold. Т.е.

sum = foldl 0 (+)


Правда, это не очень относится к Kotlin, т.к. это не чисто функциональный язык.
Битовые операции в Котлине реализованы в виде инфиксных функций or/and/xor

Как приоритеты разруливаются?

См. доку

К сожалению (а может, и к счастью), тут нельзя, как в некоторых языках, явно задать приоритет инфиксной функции.

Ха-ха, инфиксные функции в приоритетах находятся аккуратно на месте битовых операторов в C++. :)) То есть смешать and и or без скобок нормально не получится (впрочем, многие ставят скобки в любом случае), но относительно других операций приоритет привычный. Приоритет будто специально подобрали для битовых операций. :)

Битовые операции в Котлине реализованы в виде инфиксных функций or/and/xor

Как же я от этого страдал когда нужно было понавертеть много битовых вычислений.

UFO just landed and posted this here
UFO just landed and posted this here
Код в самом деле похож на Scala. По поводу IDE из введения «у которой как я понимаю, до сих пор нет нормальной IDE» — в IDEA замечательный плагин для скалы. Эклипсом я не пользуюсь, но там тоже есть поддержка скалы, и её вполне себе используют.
Ясно, просто из истории языка Kotlin читал, что при его создании, многие ругались на компанию, за то что они никак плагин под Scala не допилят)
>Подобный подход позволяет писать код в стиле LINQ
Вот вы его часто упоминаете. Не знакомы со Streams API из Java 8?
на Java 8 не работал в силу того, что у всех клиентов 7 версия стоит)) однако, киньте ссылочку, полезно будет почитать.
Из частичного применения функций.
Зачем писать 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
}
UFO just landed and posted this here
Спасибо за статью, я так понимаю это частичное пересечение (intersection) фитч двух языков, было бы неплохо глянуть на взаимо-исключающие различия.
Ну да, целью было показать то, чем языки похожи. Я уже когда читал документацию, заметил много общего с C#. Насчет различий, надо бы понять, какие они))
То ли я что-то в этой жизни не понимаю, то ли data class в Kotlin совершенно неверно позиционируют. А именно, повсюду повторяют примерно такую мантру:

Представляют интерес 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.

Я уже поднимал эту тему, но мне, к сожалению, сказали, что мой подход чрезмерно религиозен. Ну по крайней мере, буду сам стараться и просвещать по мере сил.
Мм, интересно Ваше мнение. А где можно поподробнее почитать
Мм, интересно Ваше мнение. А где можно поподробнее почитать?
Ну в философском смысле можно развести долгую дискуссию насчёт state/identity, о том, что у иммутабельных объектов их нет, и поэтому сравнение можно производить только по совокупности полей, хотя иммутабельные объекты — это никакие не объекты, а хак в ООП для эмуляции value. Проще говоря, есть примитивы вроде int/long — есть ли у них состояние? А что если мы хотим ввести свои «примитивы» вроде Vector, ComplexNumber, Address? Кстати, один такой «примитив» есть в JDK — String. Есть же объекты, которые меняют состояние, поэтому сравнивать их по состоянию некорректно, т.к. они могут иметь одинаковое состояние в какой-то момент времени, но это не означает, что это один и тот же объект. Пример — близнецы: у них очень многие параметры похожи, их даже (теоретически) могут назвать одинаково, но это всё-таки два разных человека, т.к. у них есть identity.

С практической точки зрения переопределение equals/hashCode, которые нестабильны (т.е. изменяются со временем жизни объекта) может привести к поломке HashSet/HashMap. Да и контракт hashCode явно требует его стабильности. Зависимость hashCode от состояния объекта (т.е. от поля, объявленного как var) как раз делает hashCode нестабильным.
«Стали бы Вы использовать Kotlin в своих проектах?»

Да, стал бы. По опыту, я вижу большие перспективы у подхода «одна VM — много языков» или даже Язык++ с удобным сахаром транспилируемым в просто Язык. Самым ярким примером для меня стал TypeScript, который позволял использовать плюшки ES2015 еще в 2013-ом году на продакшене, не говоря уже о его собственных плюшках. Потом появился Roslyn, сделав C# раширяемым (хотя тут главное не переборщить). Для банковской сферы, где новый код должен быть совместим со старым без вариантов, это пока единственный жизнеспособный подход что я видел чтоб не застревать на старых версиях языков годами.
UFO just landed and posted this here
Совершенно не понятно зачем на VM тащить мусор вроде inline. Это сугубо работа компилятора и нечего лезть к нему со своими указами. Если нужно выжимать максимум, для этого есть куда более подходящие языки программирования.

тут
UFO just landed and posted this here
Можно подробнее про ручной костыль, задумки и трудности?
Спецификатор `inline` в Котлин гораздо сложнее чем например в C++. Он меняет семантику функции, например влияет на вывод типов, поведение generic параметров или на вид публичного Java-api. Прирост быстродействия в случае с лямбдами это только один из эффектов.
Синтаксис не понравился. Считаю его некрасивым. Обилие двоеточий вообще кошмар.
О вкусах не спорят, но что конкретно показалось некрасивым в синтаксисе котлина?
То что мне не понравилось кому-то другому может показаться наилучшими решениями в синтаксисе. Я только высказал свое личное и субъективное мнение. Не нравиться обилие «мусора»: двоеточия (ассоциации с нелюбимым паскалем), var (я и без этого ключевого слова вижу что тут переменная), fun (я и без этого ключевого слова вижу что тут функция). Не нравится отсутствие точек с запятой (для меня это как «точка» в обычных предложениях). Так же для меня нелогичным является то что тип переменной идет после ее имени.
UFO just landed and posted this here
Я же говорю что это мое личное мнение и лично мне удобнее читать объявления слева направо как: «строка с именем Name», «константа с именем Pi» и т.д., а не «есть переменная хз какого типа с именем Name, а вот увидел ее тип строка, ну наконец-то стало понятно».
Про «парсить» вообще смешно — ЯП нужны чтобы ЛЮДЯМ было удобно писать, а главное ЧИТАТЬ.
А зачем вам вообще знать типы переменных при чтении? Обычно намного важнее семантика… или вы семантику выражаете типом? Хотя если у вас строки — то вряд ли.

(это же старый спор про implicit typing vs explicit typing)
Вот вы же и возобновляете этот спор. Я здесь ни с кем не спорил, не призывал, не отстаивал свою точку зрения, а только высказал свое мнение в нейтральной форме.
Вы же меня завуалировано оскорбляете и пытаетесь доказать что я не прав.

И да, если бы я в своем примере заменил слово «строка» на некий класс и расписал его на паре страниц кода — то вы бы не стали завуалировано меня оскорблять?
Я здесь ни с кем не спорил, не призывал, не отстаивал свою точку зрения, а только высказал свое мнение в нейтральной форме.

Вот и я высказываю свое мнение — пусть и в форме вопроса.

Вы же меня завуалировано оскорбляете

О нет, ни капли.

пытаетесь доказать что я не прав.

Нет, я пытаюсь понять, зачем вам нужно то, что вы считаете вам более удобным. Это вообще полезно иногда, причем для обеих сторон.
UFO just landed and posted this here
Меня как «пользователя» ЯП не должны волновать трудности его разработчиков.

Давайте представим себе сценку:
я разработчик, ко мне приходит заказчик, и говорит: «нарисуй мне 7 красных линий», а я ему в ответ: «мне не хочется разбирать головоломные синтаксисы, давай я нарисую 7 синих — мне так проще».

И что сделает заказчик? Он найдет того кто нарисует ему красные линии, потому что ему нужны красные, ему так удобно, ему просто так хочется в конце концов и его не волнует (и НЕ ДОЛЖНО волновать) то с какими трудностями сталкивается разработчик. И объяснять разработчику почему именно красных и именно 7 — он не обязан, и искать компромиссное решение (7 фиолетовых линий) тоже не обязан.

А нечитаемым можно сделать абсолютно любой язык (взять, например, тот же «падонкафский» русский), так что давайте не будем об этом.
UFO just landed and posted this here
fun f2(a: Int): Int {
return f1(a, 2)
}

fun f1(): Int {
return f2(1)
}


если не ошибаюсь, f2 должна возвращать f3, а не f1
>>Следствием упрощения по сравнению со Scala стали также более быстрая компиляция и лучшая поддержка языка в IDE.
Что-то и время комплиции и поддержка IDE до сих пор в котлине хромает.
Кто-нибудь уже использовал Kotlin в своих проектах? Что там с производительностью? Говорят, что хуже даже, чем у Java. Интересно было бы услышать реальные отзывы или посмотреть на бенчмарки.
Джава тормозит? Можно поинтересоваться, что не тормозит?
С++, например. Я просто интересуюсь производительностью Kotlin. Я не готов разводить холивары, просто хотел узнать мнение опытных людей.
Ну мое мнение: C++ тормозит, да еще и падает с сегфолтами. А если серьезно то Kotlin генерирует байткод очень похожий на байкод языка Java, т.е. перформанс тут не будет отличаться от Java. Но т.к. в Kotlin например можно заинлайнить лямбду, то он даже выигрывает в производительности. И таких мелких примеров много, и еще больше будет (я очень жду связки when + sealed class).

На jpoint и jet будут доклады от Дмитрия Жемерова про производительность Kotlin с JMH бенчмарками, рекомендую.
Sign up to leave a comment.

Articles