nim-lang / RFCs

A repository for your Nim proposals.
136 stars 23 forks source link

Partial generic type inference in type annotations: Support/document/experimental/discourage? #340

Open metagn opened 3 years ago

metagn commented 3 years ago

This is currently supported (intentional or not):

let x: seq[auto] = @[1, 2, 3]
echo typeof(x[0]) # int

So is this:

let x: array[3, auto] = [1, 2, 3]
echo typeof(x[0]) # int

However, this doesn't work:

let x: array[auto, int] = [1, 2, 3]
# index could be inferred to 0..2, probably only doesn't work because of array index type special behavior

This works:

type Foo[T] = object
  x: T

let foo: Foo[auto] = Foo[int](x: 3)
echo typeof(foo.x) # int

This doesn't:

type
  Foo[T, U] = object
    x: T
    y: U
  Bar[T] = object
    z: T

let foo: Foo[auto, auto] = Foo[int, Bar[int]](x: 3, y: Bar[int](z: 4))
# type mismatch: got <Foo[system.int, Bar[system.int]]> but expected 'Foo[system.auto, system.auto]'
# works if y is int or second auto is Bar[int]

Are these and other possible variations intended? Should they be supported further (like for the example above, or array indices), or declared experimental, or disallowed, or anything else?

Object constructors like Foo[int](x: 3) could also benefit from type inference like Foo[auto](x: 3) or Foo(x: 3), but that is a separate kind of type inference and has been proposed separately such as in #155.

juancarlospaco commented 3 years ago

I think stricter explicit concrete static types are better for bug-resistant code, not "auto everywhere" way. :neutral_face:

metagn commented 3 years ago

I think stricter explicit concrete static types are better for bug-resistant code, not "auto everywhere" way. 😐

I don't understand, are you saying that specifically partial generic inference is a bad kind of type inference? Is your reason the fact that it is "auto everywhere" and that's ugly? If it's not just cosmetics; can you elaborate, why is it bad here? In Scala (I think) and Rust it's commonly used, just as _ instead of auto. If it is cosmetics, I would definitely be fine with x: Foo instead of x: Foo[auto, auto], and x: Foo[auto, Bar] for x: Foo[auto, Bar[auto]], but this is not currently allowed while the auto-filled version is, for x: seq it crashes the compiler.

If your opinion is that auto is bad specifically for type annotations and not in some other place like object constructors, then I guess you could make a @[1, 2, 3].mustBe(seq) macro, but I think it would be too much pointless bearing and code on the VM rather than utilizing the compiler's codebase via the existing feature of type annotations, and give bad errors compared to normal.

Sidenote: the reason let x: Foo[auto, auto] = Foo[int, Bar[int]](x: 3, y: Bar[int](z: 4)) not working is because Foo[int, int] is Foo[auto, auto] is true, but Foo[int, Bar[int]] is Foo[auto, auto] is false. It's for any different type, so Foo[int, string] is also not Foo[auto, auto]. Because they have to be the same type, I assumed it would work if you switched to Foo[distinct auto, distinct auto] or Foo[any, any], but it still does not (if you want auto to be like a typeclass specifically in generics, this is the one you would support, but I think the original should also be supported given its existing non-typeclass behavior in proc parameters and to allow other kinds of inference like the one in this issue).

Araq commented 3 years ago

Are these and other possible variations intended? Should they be supported further (like for the example above, or array indices), or declared experimental, or disallowed, or anything else?

IMHO they can all be disallowed, the usual Nim style is to leave out the : Type part entirely rather than providing redundant (or partially redundant, partially inferred) information.

timotheecour commented 3 years ago

when T is Foo[auto, int] is useful IMO

let x: array[auto, int] = [1, 2, 3] index could be inferred to 0..2, probably only doesn't work because of array index type special behavior

this touches on parts of the compiler that are very buggy (because logic for array[N, T] is special in compiler, whereas it should use proper type declaration, eg: array[N: static (int or HSlice[int]), T] or similar, IIRC i had a WIP to fix that but didn't finish);

but auto should match a type, not a static