Type Inference for Struct/Enum Literals
IchorDev
zxinsworld at gmail.com
Fri Jul 5 13:19:44 UTC 2024
With language editions on the horizon, I thought it might be
worth taking another look at this idea, perhaps with a slightly
broadened scope. Let me know what you think.
### What & why?
For those not familiar, let's say you have a situation like this:
```d
enum Font{ normal, heading, caption }
struct Colour{ float r,g,b,a=1f; }
class TextStyle{
private Font font_;
private Colour fg, bg;
TextStyle font(Font val){ font_ = val; return this; }
TextStyle foregroundColour(Colour val){ fg = val; return this; }
TextStyle backgroundColour(Colour val){ bg = val; return this; }
}
void main(){
auto textStyle = (new TextStyle)
.font(Font.heading)
.foregroundColour(Colour(1f, 0.5f, 0.5f))
.backgroundColour(Colour(0f, 0f, 1f));
}
```
If you look at `main`, you'll see that we're repeating ourselves
a lot to call those member functions. What if we weren't forced
to write the types each time? Then it could be more like this:
```d
void main(){
auto textStyle = (new TextStyle)
.font(.heading)
.foregroundColour(.(1f, 0.5f, 0.5f))
.backgroundColour(.(0f, 0f, 1f));
}
```
Boom, that's it. For any context where an enum literal or struct
literal is being assigned/passed/etc. to something with a known
type, allow us to omit the type from the literal. I'm not really
set on any particular syntax, but here are some thoughts:
- The `.` syntax feels natural for enum literals, but not for
struct literals. This would have to mean changing the module
scope operator (perhaps to `./`? (Like to how `./` represents
'here' in a terminal) because otherwise module-level symbols
would interfere.
- My original proposal used `$`, which I still like for struct
literals, but it's a bit random.
- I don't like the C initialiser syntax (`{}`) but it could be
re-purposed for type-inferred struct literals, which would mean
we can basically merge the two.
### Implementation
The original enum literal inference DIP was [basically fully
implemented](https://github.com/dlang/dmd/pull/14650) in the end
and could easily be resurrected.
Essentially, you should be able to use inference in any situation
where the compiler can trivially infer the type from the context
of the literal. Here's a few examples with enums:
```d
enum Enum { foo,bar }
enum Mune { foo,far }
auto x = .bar; //ERR: can't use type inference when there is no
type specified anywhere!
auto x = Enum.foo;
x = .bar; //OK: `typeof(x)` is an enum with member `bar`
x = .car; //ERR: no member `bar` in enum type `Enum`!
void myFn(Enum x){}
myFn(.bar); //OK: the type of the parameter is an enum with
member `bar`
myFn(.car); //ERR: no member `bar` in enum type `Enum`!
void myOverload(Enum x){}
void myOverload(Mune x){}
myOverload(.foo); //ERR: `foo` is a member of both `Enum` and
`Mune`!
myOverload(.bar); //OK: first overload selected based on `Enum`
having member `bar`
```
The specifics of how this interacts with existing features (e.g.
array literals) very much depends on how *those* features infer
type. Here's a good example:
```d
Enum getEnum() => .bar; //OK: return type is an enum with member
`bar`
Enum x = (() => .bar)(); //it's probably not worth trying to make
this work
auto y = (int num){
switch(num){
case 0: return Enum.foo;
case 1: return .bar; //this will only work if D's compiler
frontend knows the return type of this lambda based on the first
return statement.
default: assert(0);
}
}(1);
```
### Other languages
Enum literals having their type contextually inferred is a
feature in many modern programming languages like
[Zig](https://ziglang.org/documentation/master/#Enum-Literals),
[V](https://github.com/vlang/v/blob/master/doc/docs.md#enums),
[Swift](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/enumerations/), and [Odin](https://odin-lang.org/docs/overview/#implicit-selector-expression). Java has something similar, but it's useless because it only applies to `switch` statements.
For struct literals however, the closest thing I can think of is
C's struct initialisers.
More information about the dip.ideas
mailing list