Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should we avoid naming a function same as an existing class in Kotlin? Why?

Kotlin allows to name a function same as an existing class, e.g. HashSet with initializer function could be implemented like this:

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

When used, it looks like a normal HashSet constructor:

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

Should this be avoided or encouraged and why?

like image 948
Vilmantas Baranauskas Avatar asked Jan 12 '16 19:01

Vilmantas Baranauskas


People also ask

How do you name a function in Kotlin?

To define a function in Kotlin, fun keyword is used. Then comes the name of the function (identifier). Here, the name of the function is callMe . In the above program, the parenthesis ( ) is empty.

Which is not true of functions in Kotlin?

Kotlin does not infer return types for functions with block bodies because such functions may have complex control flow in the body, and the return type will be non-obvious to the reader (and sometimes even for the compiler).

Are functions first-class in Kotlin?

Kotlin functions are first-class, which means they can be stored in variables and data structures, and can be passed as arguments to and returned from other higher-order functions.

Why are Kotlin functions known as top level functions?

These are functions that exist outside of any class, object, or interface and are defined directly inside a file. The name top-level comes from the fact that functions are not nested inside any structure and so they are at the top of the hierarchy of classes and functions.


1 Answers

UPD

In the updated coding conventions, there's a section on this topic:

Factory functions

If you declare a factory function for a class, avoid giving it the same name as the class itself. Prefer using a distinct name making it clear why the behavior of the factory function is special. Only if there is really no special semantics, you can use the same name as the class.

Example:

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

The motivation I described below, though, seems to still hold.


As said in documentation about the naming style:

If in doubt default to the Java Coding Conventions such as:

  • methods and properties start with lower case

One strong reason to avoid naming a function same to a class is that it might confuse a developer who will use it later, because, contrary to their expectations:

  • the function won't be available for super constructor call (if the class is open)
  • it won't be visible as a constructor through reflection
  • it won't be usable as a constructor in Java code (new HashSet(n, it -> "Element " + it) is an error)
  • if you want to change the implementation later and return some subclass instance instead, it will get even more confusing that HashSet(n) { "Element $it" } will construct not a HashSet but, for example, a LinkedHashSet

It's better to show it explicitly that it's a factory function, not a constructor, to avoid this confusion.

Naming a function same to a class is generally avoided in stdlib, too. Given SomeClass, in stdlib a preferred naming style for factory functions is someClassOf, someClassBy or whatever explains the semantics of the function best. The examples:

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

So, one should definitely have strong reason to have a function mimic a constructor.

Instead, a function's name might tell a user more (even everything) about its usage.

like image 102
hotkey Avatar answered Oct 12 '22 18:10

hotkey