Any plans for more type inferencing?

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.

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+

Check out the docs:

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.

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.

1 Like

Check out the docs:

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.

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

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.

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.

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.

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

Is this still a restriction if Kotlin allowed such type inference for methods with just one input? Like infix functions?

The problem is the way that JVM linking works. Linking on the JVM works only at run-time, not after compilation like most non-VM languages. There is a solution, you could use invokeDynamic to generate the function on demand on first use. There are two problems with that though: 1. It is not compatible with Java, it would be Kotlin-only violating the interoperability goals for Kotlin. 2. It only works on JVM 1.7 and up, where Kotlin by default still generates 1.6 bytecode and the language is designed to support all features on 1.6 bytecode (which is also needed for Android compatibility with older runtimes).

Of course other arguments on readability are not changed by this either.

Ah! Thanks for the clarification @pdvrieze.

I don’t understand people saying type inference for functions with blocks of code to be more complex or slower to compile or less readable than single line functions. To me they are exactly the same. You can simply trick the compiler to infer the return type for you:

fun foo() = {
     // do whatever you would in a block function here

Although the type inference is still not as smart as it could be:

fun bar() = if (Random().nextBoolean()) {
} else {

Any is resolved for fun bar() instead of Number.
All these being said I’m still not that experienced in kotlin to have a strong opinion about inferred return types. I agree that it would be a bad idea for public and protected methods(which should be used in libraries) since by changing the return type you might unknowingly break someone else’s code. But so far I’ve happily used it wherever I could. Also people should stop mentioning the likes of “hard to debug without an IDE”. How long shall we pay for the sins of vim fanatics? You can have a much better language if you assume almost everyone is going to use an IDE…

1 Like

Yes and no. In most cases I would agree. If a feature is amazing, but needs some IDE support (special highliting, displaying infered types, etc) great, I don’t care about non IDE users. If a feature can be implemented in 2 ways (one working without IDE , the other not) go for the version that doesn’t need an IDE.
Another argument is that sometimes you want explicit over implicit. Yes the compiler can infere some information (and the IDE display it to you), but sometimes you want to enforce the user to declare it. That way it won’t change accidentally, eg. I guess if you really want to, you could infere nullability for all type declarations, it’s still a bad idea.
I think the same argument can be used here. Infereing the return type for single expression functions is ok, since the programmer can easily understand the expression generating the type. It is unlikely that the return type is changed accidentally (ok you can use run to make it like a “normal” function or write expressions that are hundereds of lines long, but assume a simple function).
A function with multiple branches however is something far more complicated. Yes the compiler can easily check all branches and find the common super type, but it’s much harder for a programmer to do so. Changing something in one branch, might change the common supertype from Foo to Any.

Yes that happens with when in single expression functions as well. And there are many ways to generated branches, even within one expression (if-expression, when, etc), but in my experience programmers try to write good code.

Yes they are the same, but they aren’t used the same. Single expression functions (in my experience) are either used with a single expression(no branches) or a single when expression with simple branches (1 simple expression each branch). I (and I think many other kotlin programmers out there) consider everything else to be bad style and wouldn’t allow it through a code review.
There are some scoping functions (eg for coroutines), but in that case I strongly advise to declare the type explicitly anyways. It all goes back to intent.

You can use fun foo() = run {...} instead. No need for Unit.

We shouldn’t, but it’s sometimes nice when looking at commits/PRs on github. Yes for more complex ones (pull and look at it localy in an IDE) but being able to read code on github is still important in some cases.

I’m not that experienced; but I use apply/also whenever I want to mutate an object or something like that and use run/let whenever I want to map an object to another object(kind of like java.util.Optional#map) no matter how long or complex these functions might become.

fun foo(bar: Bar) = bar.apply{
    // 100 lines of code

is IMO better readable than:

fun foo(bar: Bar): Bar {
    // 100 lines of code
    return bar

since by reading the first line of the apply example you know that the same object is returned; But you have to read most of the 100 lines to make sure nothing else is returned in the second example.

Wouldn’t good programmers continue to write good code even if we allow type inference for functions with blocks while bad programmers can already write bad code using run?

Thanks for the tip :+1:

Good code should be easy to write, while bad code should take effort.
Of cause it’s not allways possibel to design for that, but enforcing the return type on block functions is a step in that direction. Enforcing it for single line functions would make code less readable in case of short expressions, so it’s not enforced.

Your example with also is ok, but a kotlin programmer would easily be able to infere the type from that and there is no real chance that you change it accidentally. I agree that in your example apply is better. But then it kinda follows my rule from above. The type is infered by the first simple expression bar.apply. The rest is just some added code, that does not change the return type.
In the end there are no perfect rules for good code. It depends on the situation.

PS: you can format code by using either a singel ` to inline code or 3 of them to create a code block. I hope that makes sense. The problem is I can’t really show it since it will just convert it to code :frowning:

Yeah, selecting your code block and clicking on ‘Preformatted text’ button indents the code block which does nothing. Probably a bug.