Any plans for more type inferencing?


#1
fun square(x: Int) : Int { return x*x }

fun cube(x) { return square(x)*x } // error

The type signature of cube has been sufficiently specified, and the compiler should know that. Type inferencing languages such as Haskell have been doing this for decades.

I really hope the answer is “maybe in the future”, and not some “more explicit code is good” propaganda. That’s the problem of Java – the problem kotlin was presumably aiming to fix. Programmers should not have to overspecify.


#2

EDIT: You can already do this with the return type as SackCastellon points out below.

As far as inferred params, that would be difficult to infer without assuming Any?

More explicit code is good:

If you’re interested, here’s play-by-play of debugging poorly written Groovy code (lack of type information) without an IDE.

How to find the type of an inferred variable without an IDE

Looking up an error on some variable foo.
No type information on the use site.

Find foo's declaration.
No type information: Inferred from method createFoo().

Find where createFoo() is declared.
No type information.

Read through createFoo() for a return.
Found multiple returns (Will need to find a common supertype).
No type information: return variables have inferred types.

*Repeat the above steps for both return types. Two types are found.

Search through both types to find a common supertype.

Use the common supertype to infer createFoo()'s return type

Realize that you missed createFoo() overrides a parents method with no type information as per the proposal

The parent method returns two inferred things (do we assume they are the common supertype? We can’t be sure).

*Repeat all of the steps above for each returned value to find a new common supertype


Possible time to find out what type foo is without an IDE: Years
Files to read: 1000+


#3

Check out the docs: https://kotlinlang.org/docs/reference/functions.html#single-expression-functions


#4

Hence it would be consistent to allow this for parameters also. Any argument against could also be applied to the return type.

I find the OP’s request to be valid, but I don’t have any preference in neither direction.


#5

Well it might be problematic due to function overloading. What type would x be in cube if there was a square version for long, float and double as well as int? Could it take any of the above?

fun foo(i: Int) = i.toDouble()
fun foo(f: Float) = f.toDouble()

fun bar(a, b) = foo(a) + foo(b)

Also would bar then generate 4 different overloads automatically? Or would this type inference only work if there is only one version of foo. In which case this would lead to situation where extending a library with an overload of a function would break existing code elsewhere. So stdlib could never be extended? I don’t think this would end well.


#6

Check out the docs: https://kotlinlang.org/docs/reference/functions.html#single-expression-functions

Blocks should infer return types; that’s the point. There is no good justification for them not doing type inference apart from “not yet implemented”. The documentation is actually what initially stoked my fear that the Java mindset of “programmers must do busy work because it’s good for them” may still (ironically) have a grip here. To wit,

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).

But the whole point is that it’s non-obvious to the programmer. That’s the reason you do type inferencing. The compiler should know when you did something wrong. The programmer shouldn’t overspecify. I can’t tell you how many times SBCL’s inferencing on result values has saved my ass. If Lisp can do it then kotlin sure as hell can. I can appreciate answers like “too complex for now” or “not yet implemented”. What I fear are rationalizations that entrench a state of poverty that echo the rationalizations for sticking to Java.

Also would bar then generate 4 different overloads automatically?

Well, naturally, as in other languages, the compiler knows what’s needed and only generates those.

How to find the type of an inferred variable without an IDE

It seems to me that this is apples and oranges. Groovy is very dynamic and often duck-typed. As with Ruby (I think the rhyme was intentional), the dynamism gives flexibility and power, with the whole point being that even the code doesn’t know actual types. That’s the pro and the con. But even putting that point aside, there’s no reason an IDE would be required to inspect objects. Why wouldn’t an object have its own describe() (or some such) method that describes itself? That’s what you would do when you are duck-typing.


#7

This has been discussed before, but I can’t find the thread. I believe the conclusion was that compilation performance degrades too much.


#8

It can’t. The compiler might know which are needed if you are creating an application, but in case of a library you need all variances. Also my example was just to make a point. Stack functions like this a bit deeper and you would need to generate hundreds of functions, which would be a nightmare if you want java interop, which is one of the core features of kotlin.

Yes and kotlin decided it’s a con. If it is non obvious to the programmer what the type is, that is a problem IMO. I just leads to unexpected behavior and bugs.

I don’t understand your argument. You’re saying that a simple text editor, which supports syntax highlighting at best, can somehow tell you the inferred type of a function, without being considered a full IDE? Or are you planning on compiling the code and then checking the resulting objects for their types? Because either you have to read bytecode or you need some special tool for that as well.

There might be some dialects of lisp which are statically typed, but I thought lisp in general does not have static typing so the comparison to lisp is not really relevant in this regard. If you want a language with dynamic types, maybe Kotlin is not the best option.


#9

The compiler might [k]now which are needed if you are creating an application, but in case of a library you need all variances.

Well if one were to really implement type signatures with inferencing, one would write out blobs describing them (as type inferencing languages do). That’s how you only instantiate the ones you need. This puts more work on the linker for Java interop, but the theme here is letting the tools do the work and letting the programmer be concise. Note the linker needn’t be aware of kotlin in particular; it just needs to recognize certain blobs describing type-instantiated functions. One could think of it as a future Java feature that only kotlin implements.

If it is non obvious to the programmer what the type is, that is a problem IMO. I just leads to unexpected behavior and bugs.

But the whole point is that the same function in code can return different types. We wish to avoid the busy work mindset of Java – to avoid manually writing out one version which returns float and another which returns double. We wish to avoid overspecifying. The constraints on the type are sufficient – that’s what the programmer needs to pay attention to. The exact type is immaterial to the logic of the code as long as the type constraints are met.

You’re saying that a simple text editor, which supports syntax highlighting at best, can somehow tell you the inferred type of a function, without being considered a full IDE?

I’m saying there typically isn’t an inferred type in the first place, per the design and purpose of the language. For instance, the language was designed so that a function expecting a certain type of object would also accept a mock object having no relation to anything the function has seen before. Being cavalier with types is a feature of that particular language, not a bug. That’s why it’s apples and oranges with respect to kotlin.

There might be some dialects of lisp which are statically typed, but I thought lisp in general does not have static typing so the comparison to lisp is not really relevant in this regard.

Static types may be optionally declared in Common Lisp. SBCL makes use of those declarations for type inferencing. The point here is that if Lisp – where type declarations are optional – can do type inferencing, then kotlin – where types are already known – sure as hell can. The doc I quoted seemed to suggest that inferencing wouldn’t work well for blocks, but that’s just not true. It works well in SBCL, where it’s harder to do.


#10

With the small problem that this needs to be supported by the jvm bytecode, which it is not.

Yeah, that’s what generics are for. The only problem with them is FloatArray, etc vs Array<Float> but again that is a limitation of the jvm bytecode and not kotlin.

Are we still talking about kotlin? Because I always thought Kotlin is strict about types per design. The problem is not that it is not possible to infer the types of a function parameter. The problem is in the cost of it. First the is the performance as jstuyts pointed out. Also there is the problem I described with the way it is compiled to bytecode. Kotlin does not have the luxury of deciding what the bytecode supports, it is bound by the features of the JVM and what you ask for would not work as I explained in my first post.

As for return types. Yes I sometimes wish that I don’t have to specify the type for simple code blocks. But as soon as you deal with multiple branches returning at different places in a function I think it is good that the type needs to be declared, because it describes intention and is therefor not unnecessary grunt work. Could the compiler infer the type? Yes. Should it, I’m not so sure.