Not sure if this is mentioned elsewhere, but why d...
# language-proposals
x
Not sure if this is mentioned elsewhere, but why does `class`es have their templates declared after their name, whereas `fun`ctions have their templates declared before their name? shouldn’t they follow the same notation?
Copy code
fun <T> Foo(bar: T) = Unit
class <T> Bar(foo: T) // wont compile
or
Copy code
fun Foo<T>(bar: T) = Unit // wont compile
class Bar<T>(foo: T)
j
Probably because its that way in java
Which might be related to because of how in java the return type is before the method name
x
Yeah, it does look like a bit of design inconsistency kotlin adopted from java
d
Type parameter of class is part of its type, and on use-sites you write
val x: Base<T>
, so class declaration syntax is consistent with use site On the other hand type parameter of function can be used as receiver type, so if declare
T
after function name, that it can be referenced before declaration, which hurts readability of code:
Copy code
fun T.foo<T>() {}
// vs
fun <T> T.foo() {}
2
f
I can and sometimes have to use the type on the call side of a function as well, seems like a weak argument.
m
Yup, the only feasible argument I see is to avoid using generic extension type before its declaration, which 1) is IMO neither that common nor non-readable (works well in C#) and 2) as discussed in KEEP with upcoming context receivers it will most probably have to be the used this way, i.e.
context(T) fun<T> foo(){}
. Otherwise I see every other point on why this should be the other way: 1.
Copy code
declaration            |              usage
class Foo<T>(bar: Int) //name, type     Foo<String>(1) //name, type
  fun<T> foo(bar: Int) //type, name     foo<String>(1) //name, type
2. The principle of Kotlin says the name is more important than types and parameters and should be first, but type parameters on functions go against that rule and thus often obfuscate the declaration. 3. With classes the order is more consistent:
class
, name, type parameters, value parameters. Type and value parameters are both parameters and thus are next to each other. With functions it is
fun
, type parameters, name, value parameters. Transition from
fun<T> foo() {}
to ``fun foo<T>() {}``would probably be impractical in general but I'd appreciate if both ways were made possible, maybe behind a compiler flag.
x
I think i agree with @dmitriy.novozhilov, that for `fun`ctions, it makes sense to declare templates before the name, so that extension/receiver can be based on that. I also agree with @mcpiroman that with the upcoming
context()
proposal, the above point becomes obsolete. Only downside of naming the templates after the name is when there’s additional modifiers applied to the template type. for instance
Copy code
context(T)
inline fun T.foo<reified T: Any>(): T
i can see this becoming less readable compared to declaring types upfront