Не следует ли нам назвать функцию, аналогичную существующему классу в Котлине? Зачем?

Kotlin позволяет назвать функцию такой же, как и существующий класс, например, HashSet с функцией инициализации может быть реализована следующим образом:

 fun <T> HashSet(n : Int, fn: (Int) -> T) = HashSet<T>(n).apply { repeat(n) { add(fn(it)) } } 

При использовании он выглядит как обычный конструктор HashSet :

 var real = HashSet<String>() var fake = HashSet(5) { "Element $it" } 

Следует ли это избегать или поощрять и почему?

UPD

В обновленных соглашениях о кодировании есть раздел по этой теме :

Заводские функции

Если вы объявляете фабричную функцию для класса, не указывайте ему то же имя, что и сам класс. Предпочитайте использование отдельного имени, дающее понять, почему поведение фабричной функции является особенным. Только если нет специальной семантики, вы можете использовать то же имя, что и класс.

Пример:

 class Point(val x: Double, val y: Double) { companion object { fun fromPolar(angle: Double, radius: Double) = Point(...) } } 

Мотивация, описанная ниже, по-прежнему сохраняется.


Как сказано в документации о стиле именования :

Если у вас есть сомнения по умолчанию для кодов Java, таких как:

  • методы и свойства начинаются с нижнего регистра

Одной из сильных причин избежать присвоения функции, аналогичной классу, является то, что она может запутать разработчика, который будет использовать его позже, потому что, вопреки их ожиданиям:

  • функция не будет доступна для вызова суперконструктора (если класс open )
  • он не будет отображаться как конструктор через отражение
  • он не будет использоваться в качестве конструктора в Java-коде ( new HashSet(n, it -> "Element " + it) является ошибкой)
  • если вы хотите позже изменить реализацию и вернуть экземпляр подкласса, это будет еще более запутанным, что HashSet(n) { "Element $it" } будет строить не HashSet а, например, LinkedHashSet

Лучше показать это явно, что это не фабричная функция, а не конструктор, чтобы избежать этой путаницы.

Именовать функцию, аналогичную классу, также можно избежать в stdlib. Учитывая SomeClass , в stdlib предпочтительный стиль именования для заводских функций – это someClassOf , someClassBy или что-то SomeClass , что лучше объясняет семантику функции. Примеры:

  • generateSequence { ... } и sequenceOf(...)
  • lazy { ... } и lazyOf(...)
  • compareBy { ... }
  • listOf(...) , setOf(...) , mapOf(...)

Таким образом, нужно обязательно иметь вескую причину, чтобы функция имитировала конструктор.

Вместо этого имя функции может рассказать пользователю больше (даже все) о его использовании.

Я согласен с + горячей клавишей. Вероятно, лучше избегать путаницы в этом случае.

Если он используется только внутри, и все остальные разработчики (если есть) в порядке с ним, я бы сказал, чтобы пойти на это. Python признает эту идею, и я ее люблю. Черт возьми, они идут в обоих направлениях, и вы можете назвать класс в функциональном случае, если он больше похож на то, что он действует как функция. Но, Python не должен иметь дело с Java interop, поэтому определенно не делайте этого для общедоступного кода.