why is it ```val x: MutableSet = mutableSetOf()```...
# getting-started
r
why is it
Copy code
val x: MutableSet = mutableSetOf()
instead of
Copy code
val x: MutableSet = MutableSet()
?
j
MutableSet
is an interface, so it can't be constructed directly.
mutableSetOf()
is a top-level function for constructing a
MutableSet
implementation with passed in values, which returns an empty set when no values are passed.
j
Still, the function could have been called
MutableSet()
to look like a constructor. I don't know why it wasn't. Maybe to avoid confusion like this, maybe because of the vararg.
j
Yeah, I see it as a design choice to make its usage more explicit.
c
My guess is because
MutableSet()
(or
List()
,
MutableMap()
, etc.) all imply a constructor-like behavior, where you get a new distinct object as a return value each time. But this isn’t true, because the factory function returns different implementations of the collection based on how many items are passed to it. In the case that no items passed in to a read-only collection, you are actually given an instance of a singleton
EmptySet
,
EmptyMap
,
EmptyList
, etc. which is not distinct. A new object isn’t necessarily created with each call, like you’d expect form a constructor, so instead a factory function is more appropriate. And then there are mutable versions of the read-only collections which simply use the same syntax for consistency, even though they do always give a new instance.
👍 3
💡 1
blob think smart 1
e
we do have
Array
and
List
constructor-like functions though
(well I guess for
Array
it's an actual constructor, handled by some compiler magic, so let's ignore that for this discussion)
my view is that some of this is down to timing of when the language was ready versus when they settled on certain API patterns. perhaps if builder inference were there from the start, we would have
List {}
Set {}
etc. instead of
buildList {}
buildSet {}
etc.
💡 2
c
^ I was also thinking that. The early days of Kotlin were very strongly inspired by Groovy, where they often took features directly from Groovy by used named functions instead of operators or arcane syntax, to make it read more like spoken English
k
listOf
and the
List
factory function are both factory functions that produce a list, but they have different meanings: if, during the early development of the library, we had just defined
List
as the sole factory function, we wouldn't be able to call these two functions with the same parameters but with very different meanings:
Copy code
val x = listOf(2, { Random.nextInt() })
val x = List(2, { Random.nextInt() })
(That is a very contrived example though.)
2
j
Honestly the example doesn't look very contrived to me. That's a very fair point
It's nice that we can distinguish the vararg function for creating a list of known elements from the fake constructor function that generates a list of known size based on a factory
👍 1
c
A new object isn’t necessarily created with each call, like you’d expect form a constructor, so instead a factory function is more appropriate. And then there are mutable versions of the read-only collections which simply use the same syntax for consistency, even though they do always give a new instance.
This would make sense, but the style guide says the opposite:
Factory functions used to create instances of classes can have the same name as the abstract return type:
```interface Foo { /*...*/ }
class FooImpl : Foo { /*...*/ }
fun Foo(): Foo { return FooImpl() }```
https://kotlinlang.org/docs/coding-conventions.html#function-names
k
It seems intuitive that a function called
List
would always create a new instance because it looks like a constructor call. And indeed it does.
List(0) {0}
creates a new empty list instance, while
listOf()
returns the existing instance
EMPTY_LIST
.