Project

General

Profile

Feature #11925

Struct construction with kwargs

Added by prijutme4ty (Ilya Vorontsov) almost 3 years ago. Updated 11 months ago.

Status:
Closed
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:72595]

Description

Propose to make Struct subclass constructors which accept keyword arguments. Not sure, if it's reasonable to allow .new accept kwargs, so may be should use different method named like .create:

  Point = Struct.new(:x,:y, :color)
  pt_1 = Point.create(x: 1, y: 2) # => Point<x: 1, y: 2, color: nil>
  pt_2 = Point.create!(x: 1, y: 2) # => ArgumentError, color not specified.

It will greatly simplify work with big structures, especially in cases when struct layout changes and for cases when structure can have lots of non-significant values. It also allows simpler ways to use implement default values for struct members.


Related issues

Related to Ruby trunk - Feature #15076: Struct to raise error when keyword arguments used but not enabledRejected
Related to Ruby trunk - Feature #15222: Add a way to distinguish between Struct classes with and without keyword initializerOpen
Has duplicate Ruby trunk - Feature #9209: Struct instances creatable with named argsClosed
Has duplicate Ruby trunk - Feature #13272: Keyword argument to instantiate a subclass of StructClosed

Associated revisions

Revision 02015974
Added by k0kubun (Takashi Kokubun) 11 months ago

struct.c: add keyword_init option to Struct.new

to initialize struct with keyword arguments.

[Feature #11925] [close GH-1771]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61137 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 61137
Added by k0kubun (Takashi Kokubun) 11 months ago

struct.c: add keyword_init option to Struct.new

to initialize struct with keyword arguments.

[Feature #11925] [close GH-1771]

Revision 61137
Added by k0kubun (Takashi Kokubun) 11 months ago

struct.c: add keyword_init option to Struct.new

to initialize struct with keyword arguments.

[Feature #11925] [close GH-1771]

History

#1 [ruby-core:72611] Updated by ksss (Yuki Kurihara) almost 3 years ago

Hi.

I have thought the same thing that want to use kwargs in Struct class.

But I can't come up with a good API.

Finally, I made a gem. https://github.com/ksss/type_struct

#2 Updated by naruse (Yui NARUSE) over 2 years ago

  • Assignee deleted (ruby-core)

#3 [ruby-core:75584] Updated by shyouhei (Shyouhei Urabe) over 2 years ago

We looked at this issue in yesterday's developer meeting. Nobody there was against the functionality -- but the name. create! doesn't sound appropriate at all. create also not that obvious for non-English speakers like us that it expects keywords.

#4 [ruby-core:77757] Updated by herwinw (Herwin Quarantainenet) about 2 years ago

What about new_from_kwargs(**kwargs) ? It's a bit long, but it describes the functionality exactly.

#5 [ruby-core:77760] Updated by herwin (Herwin W) about 2 years ago

https://github.com/ruby/ruby/pull/1468

A proposal for an implementation.

irb(main):001:0> MyClass = Struct.new(:a, :b, :c)
=> MyClass
irb(main):002:0> MyClass.new_from_kwargs(a:1, c: 3)
=> #<struct MyClass a=1, b=nil, c=3>
irb(main):003:0> MyClass.new_from_kwargs(1, 2, 3, b: 3)
=> #<struct MyClass a=1, b=3, c=3>
irb(main):004:0> MyClass.new_from_kwargs(d: 4)
NameError: no member 'd' in struct
    from (irb):4:in `new_from_kwargs'
    from (irb):4
    from ./irb:11:in `<main>'
irb(main):005:0> MyClass.new_from_kwargs(1, 2, 4, 5, b: 3)
IndexError: offset 3 too large for struct(size:3)
    from (irb):5:in `new_from_kwargs'
    from (irb):5
    from ./irb:11:in `<main>'
irb(main):006:0> 

#6 [ruby-core:77762] Updated by nobu (Nobuyoshi Nakada) about 2 years ago

Herwin W wrote:

irb(main):003:0> MyClass.new_from_kwargs(1, 2, 3, b: 3)
=> #<struct MyClass a=1, b=3, c=3>

Why does new_from_kwargs accept other than keyword arguments?

#7 [ruby-core:77763] Updated by herwin (Herwin W) about 2 years ago

To be prepared for "the great unification of constructors" of course.

It looked like a pretty logical step to support while I was coding this. It's also pretty easy to remove again

#8 Updated by shyouhei (Shyouhei Urabe) almost 2 years ago

  • Has duplicate Feature #9209: Struct instances creatable with named args added

#9 [ruby-core:79181] Updated by ko1 (Koichi Sasada) almost 2 years ago

Another idea is introducing another method to define own struct, such as T = Struct.define(:a, :b); T.new(a: 1, b: 2) and so on.
(just idea) Moreover we can extend Struct with some properties, like: Struct.define(:a, b: :read_only).

These ideas are provided by another person.

#10 Updated by nobu (Nobuyoshi Nakada) over 1 year ago

  • Has duplicate Feature #13272: Keyword argument to instantiate a subclass of Struct added

#11 [ruby-core:84110] Updated by k0kubun (Takashi Kokubun) 11 months ago

Similar to one commented by ko1, how about this interface?

T = Struct.new(:a, :b, keyword_argument: true)
T.new(a: 1, b: 2)

As keyword_argument is long, another option is:

Struct.new(:a, :b, keyword_args: true)

#12 [ruby-core:84147] Updated by k0kubun (Takashi Kokubun) 11 months ago

In case that my suggestion of the name is accepted, I wrote a patch for Struct.new(:a, :b, keyword_args: true).
https://github.com/ruby/ruby/pull/1771

#13 [ruby-core:84184] Updated by knu (Akinori MUSHA) 11 months ago

What if Struct.new([:a, :b]) created a class with the desired constructor?

#14 [ruby-core:84186] Updated by matz (Yukihiro Matsumoto) 11 months ago

I vote for the keyword argument (e.g. keyword_init:) to Struct#new.

Matz.

#15 [ruby-core:84187] Updated by herwin (Herwin W) 11 months ago

knu (Akinori MUSHA) wrote:

What if Struct.new([:a, :b]) created a class with the desired constructor?

If you'd compare the two possible constructors:

Struct.new(:a, :b)
Struct.new([:a, :b])

There is nothing in the second one that would indicate the second creates a keyword constructor. If I hadn't read this discussion, I would just expect them to behave the same.

#16 Updated by k0kubun (Takashi Kokubun) 11 months ago

  • Status changed from Open to Closed

Applied in changeset trunk|r61137.


struct.c: add keyword_init option to Struct.new

to initialize struct with keyword arguments.

[Feature #11925] [close GH-1771]

#17 [ruby-core:84188] Updated by k0kubun (Takashi Kokubun) 11 months ago

As Matz approved, I committed only keyword_init option which is equivalent to "Point.create(x: 1, y: 2)" in original suggestion. If you still want "Point.create!" version which raises ArgumentError (keyword_init initializes unspecified fields with nil), please file another ticket.

#18 Updated by nobu (Nobuyoshi Nakada) 2 months ago

  • Related to Feature #15076: Struct to raise error when keyword arguments used but not enabled added

#19 Updated by k0kubun (Takashi Kokubun) about 1 month ago

  • Related to Feature #15222: Add a way to distinguish between Struct classes with and without keyword initializer added

Also available in: Atom PDF