nim-lang / RFCs

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

Object initialization shortcuts #254

Closed al6x closed 3 years ago

al6x commented 3 years ago

A shorter way to pass parameters during object initalization, read rendered markdown

Short example:

type
  Unit = object
    race: string
    hp:   int
    name: string

let
  race = "Protoss"
  hp   = 100
echo Unit(race, hp, name: "Zeratul")
echo Unit(race, hp, name: "Artanis")

echo Unit(:race, :hp, name: "Zeratul") # Alternative way

CC @dom96

mratsim commented 3 years ago

The syntax is ambiguous regarding the let scope. This is better

type
  Unit = object
    race: string
    hp:   int
    name: string

with(Unit):
  race = "Protoss"
  hp   = 100
  echo Unit(race, hp, name: "Zeratul")
  echo Unit(race, hp, name: "Artanis")

  echo Unit(:race, :hp, name: "Zeratul") # Alternative way

So that the default value are scoped.

Alternatively we can expand using which currently supports

using
  c: Context
  n: Node
  counter: int

proc foo(c, n) = ...
proc bar(c, n, counter) = ...
proc baz(c, n) = ...

proc mixedMode(c, n; x, y: int) =
  # 'c' is inferred to be of the type 'Context'
  # 'n' is inferred to be of the type 'Node'
  # But 'x' and 'y' are of type 'int'.
al6x commented 3 years ago

Hmm, with and using feels too complicated, the whole point of this shortcut is to be trivial and be used on the fly.

The need to know about and use special keywords like with or using kinda defeat the whole point of having such shortcut. In the end code will be even more complicated than without using this shortcut at all.

mratsim commented 3 years ago

I think the only thing needed is to have object constructor not require the field names just like a proc call.

i.e. today we have to do MyConstructor(a: x, b: y, c: z) and we should allow MyConstructor(x, y, z)

bluenote10 commented 3 years ago

I think the only thing needed is to have object constructor not require the field names just like a proc call.

Wouldn't that imply that changing the order of the fields in the type definition is a breaking change?

Rust also has this shorthand that the field name can be omitted if and only if the local variable has the same name, which in my opinion is a nice tradeoff in terms of conciseness and safe semantics.

mratsim commented 3 years ago

I think the only thing needed is to have object constructor not require the field names just like a proc call.

Wouldn't that imply that changing the order of the fields in the type definition is a breaking change?

Yes but I think this pattern is common

type Foo = object
  a: int
  b: float
  c: string

proc initFoo(a: int, b: float, c: string): Foo =
  result.a = a
  result.b = b
  result.c = c

let
  a = 1
  b = 2.0
  c = "three"

let x = initFoo(a, b, c)

or

type Foo = object
  a: int
  b: float
  c: string

let
  a = 1
  b = 2.0
  c = "three"
let x = Foo(a: a, b: b, c: c) 

and both would be replaced by

type Foo = object
  a: int
  b: float
  c: string

let
  a = 1
  b = 2.0
  c = "three"
let x = Foo(a, b, c) 

Now, do people often change the field order for public objects, I don't know. The Rust-like suggestion is interesting.

timotheecour commented 3 years ago

This can and should be done via a macro instead of compiler patch.

echo Unit.init(race, hp, name: "Zeratul")
timotheecour commented 3 years ago

closing, see https://github.com/nim-lang/RFCs/pull/225; please re-open as an issue, not a PR