Pull to refresh

Comments 42

Насчёт работы с датами — можно было чуть большим количеством кода получить даже более красивые результаты


data class IntervalInfo(amount: Long, type: ChronoUnit)
operator fun Date.minus(interval: IntervalInfo):Date{…}
operator fun Date.plus(interval: IntervalInfo):Date{…}
val Int.months = IntervalInfo(this, ChronoUnit.MONTHS)
val Int.days = IntervalInfo(this, ChronoUnit.DAYS)

и использовать как-то вроде


val before = date - 3.days
val after = date + 2.months

Ну а если вы не на 8й джаве пока — тогда можно свой аналогийчный энам изобрести.

Мне не очень понравилась мысль перегружать примитивы. Это хорошо для DSL, но в продакшен коде будет приводить к проблемам, так как на days и months не остановишься, и скоро у простого Int будет api не меньше чем у list
Ну они не сами же вам в код попадают. Где надо — там заимпортировали, где не надо — не импортируете. То есть в том месте где у вас будет работа с датами — там и будете красивый код писать.
Да, только IDE будет подсказывать все. Проверил
Мне кажется что если оно к месту — то почему бы не писать красиво там где можно писать красиво?
Может, это чопорно, но по мне Int не должен знать о ChronoUnit, Date и прочем. Написав такой extension, мы расширяем api Int такими знаниями.
Вариант ниже решает эту проблему: DAYS знает о Int, но не наоборот.

Красиво — это не пихать мульйон методов в один тип. Любой нубас может наговнокодить божественных и несолидных объектов, когда это красивым стало?

Ну не знаю. Должен ли Int знать про Long? А про BigInteger? В котлине знает. По мне — это просто удобные эксплицитные конвертеры.

Но в общем можно и не использовать свой data-класс, а писать как-то вроде


val before = date - Pair(3, DAYS)
Тогда возвращаясь к локаничности, но без перегрузки примитивов. Я, навреное, на это перепишу свой код
val before = date - DAYS*3
before = date - 3.days

выглядит вполне в духе Ruby.

а чем отличаются
val list1: List?
и
var list9: List?
Тем, что первый нельзя заменять после инициализации. В случае с локальной переменной var нужен не часто, а вот в случае поля — вполне.

Возможно, rfq не заметил, что там разные ключевые слова

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

Видимо, упор идёт на то, что IDEA заметно выделяет локальные переменные с var.

Отвратительные ключевые слова — сливаются воедино, я тоже не сразу заметил, что первое слово в примере то разное! Очень неприятное решение от языка, который стремится уменьшить количество ошибок. Лучше бы какое-нибудь "var/let" заюзали

Сорри, это было в предыдущую ветку сообщение

возможно, взяли пример со scala
Ага, в Скала это настолько же ужасно.

А чем "невозможный на Java" пример с assertFail отличается от использования @Test(expected = ArrayIndexOutOfBoundsException.class)?

Я бы спросил по-другому. Чем с точки зрения красоты отличаются вот эти две строчки:


Kotlin: assertFail<ArrayIndexOutOfBoundsException> { arrayOf(1, 2)[3] }
Java: assertFail(ArrayIndexOutOfBoundsException.class, () -> arrayOf(1, 2)[3])

наверное тем, что конструкция на Java будет жить только в JVM начиная с 8 версии, а на Kotlin и в JVM 7 и даже 6?

Согласен, не слишком удачный пример. В куске кода чуть выше (про репозиотрии) был более инетересный вариант (сейчас продублирую в статье). Это в случае, если класс писал не ты и T просто нет.
inline fun <reified T, ID: Serializable> CrudRepository<T, ID>.find(id: ID): T {
    return findOne(id) ?: throw ObjectNotFound(id, T::class.qualifiedName)
}

Я бы разделил немного по-другому. Важно не то, писал ли ты класс — а то, может ли параметр шаблона быть выведен из параметра функции. Если может — то Kotlin дает более красивый код чем Java. Если нет — то и разницы нет.


В примере с репозиторием параметр шаблона T выводится из скрытого параметра метода this (вроде бы).

Это inline функция, она не существует в runtime, вместо этого она разворачивается при компиляции в месте использования. Поэтому, T доступно — в compile time она ещё не стерта
В примере с репозиторием параметр шаблона T выводится из скрытого параметра метода this (вроде бы).

Решил объяснить как работает эта магия. Из this T в общем случае не выведешь, насколько я помню. Я когда-то пробовал, решил что легче каким-то образом передавать Class T. Источник

Если this имеет тип CrudRepository<T, ID> — то для компилятора нет проблем "достать" из него T.

В случае assertFail это не сработает, так как нет объекта, из которого можно вытащить T. А механизм один.

Так я про это и говорю! Именно поэтому при вызове assertFail нужно явно писать тип в угловых скобках, а при вызове find — не нужно.


А это, в свою очередь, приводит к тому, что assertFail на Kotlin выходит ничуть не красивее чем аналог на Java. Функция же find на Kotlin получается красивее чем на Java, потому что у нее "исчезает" один параметр.

Кроме отсутсвия статической типизации, что не делает его Safe, что для меня является основным приемуществом языка

Ожидал более практических результатов в этой статье.
Я, например, пробовал компиляцию в js — как proof-of-concept интересно, но тулинг и поддержка студии (основы "философии") — отвратительные, их практически нет.


Некоторые идеи, представленные здесь — далеко не новые, а уже давно "витают" в сообществе. В Kotlin'е просто использованы свежие идеи. Но от влияния Java он никуда не денется: на некоторые issue JetBrains так и говорит: мы сделали это так, потому что это так в Java.

Практический результат — написанный проект мне нравиться, язык действительно помогает сделать код безопаснее, код хорошо читается. К сожалению, влияние в мелочах, поэтому ужать всё это в одну статью не получилось.
UFO just landed and posted this here
Я полгода пишу на Kotlin, и всё что смог припомнить:
1. Extension написанный на Kotlin нельзя вызвать из Java. Было бы странно, если бы можно было.
2. Если написать на Kotlin класс и отнаследоваться от него на Java, могут возникнуть некоторые сложности.
UFO just landed and posted this here
У меня проект на Spring Boot, Hibernate и JSF, final решается на раз плагином
С интерфесами вряд ли будут проблемы, я говорил про наследование классов.
Насчет 100% — да, я не стал это упоминать в статье и не считаю это «нарушением интеропа», так как причиной этому то, что в Kotlin немного больший функционал (в основном, за счет компилятора), чем в Java, и, естественно, к нему нет прямого доступа из Java.
а еще косяки с дженериками
Это вы о чем?

метод с inline + reified из java не вызвать. Интерфейс определенный в java это SAM, но, внезапно, интерфейс определенный в kotlin нет. В интерфейсах @JvmStatic/@JvmField не работает и тд. В какой-то степени это должно радовать, потому что в котлине есть фичи, которые невозможно повторить в джаве, но тогда нужно быть скромнее про 100% интероп.

Сам ещё не использовал, но, судя по всему, это может сильно изменить подход к многопоточному программированию.

Не совсем ясно причем тут многопоточное программирование…

Sign up to leave a comment.

Articles