Project

General

Profile

Feature #8563

Instance variable arguments

Added by Tsuyoshi Sawada over 3 years ago. Updated 2 months ago.

Status:
Assigned
Priority:
Normal
[ruby-core:55596]

Description

Often times, people want to assign given arguments to instance variables, especially inside the method initialize:

def initialize foo, bar, buz
  @foo, @bar, @buz = foo, bar, buz
  ...
end

I propose to let method definition take instance variables as arguments so that:

def initialize @foo, @bar, @buz
  ...
end

would be equivalent as above.


Related issues

Duplicates Ruby trunk - Feature #5825: Sweet instance var assignment in the object initializer Assigned
Duplicated by Ruby trunk - Feature #12578: Instance Variables Assigned In parameters ( ala Crystal? ) Feedback

History

#1 [ruby-core:55598] Updated by Nobuyoshi Nakada over 3 years ago

  • Category set to syntax
  • Target version set to Next Major
  • Assignee set to Yukihiro Matsumoto
  • Status changed from Open to Assigned

#2 [ruby-core:55600] Updated by Matthew Kerwin over 3 years ago

Question: would this be valid?

def foo(@foo=@foo) end

Asking here, because #5825 as written only talks about initialize method, and the above construct wouldn't make sense there.

#3 [ruby-core:55601] Updated by Yukihiro Matsumoto over 3 years ago

From my POV:

def initialize(@foo, @bar)
end

does not express intention of instance variable initialization. I'd rather add a method like

define_attr_initialize(:foo, :bar)

to define a method of

def initialize(foo, bar)
  @foo = foo
  @bar = bar
end

Matz.

#4 [ruby-core:55602] Updated by Tsuyoshi Sawada over 3 years ago

It could also be used besides initialize:

def update_something foo
   do_update_something(@foo = foo)
   ...
end

would become

def update_something @foo
   do_update_something(@foo)
   ...
end

#5 [ruby-core:55603] Updated by Nobuyoshi Nakada over 3 years ago

phluid61 (Matthew Kerwin) wrote:

Question: would this be valid?

def foo(@foo=@foo) end

In generic,

foo = foo

is valid always.

#6 [ruby-core:55604] Updated by Charles Nutter over 3 years ago

Worth pointing out that blocks used to support this:

1.times { |@foo| ... }

Basically, it supported anything you can have on the LHS of a normal assignment:

foo.bar { |a, @b, @@c, D, e.val, f[0]| ... } 

I believe it was taken out in 1.9 because it made argument processing a lot more complicated, but then 1.9 added the ability to do multiple-assignment grouping, default values, and other masgn features to all argument lists anyway. It doesn't seem like it would be too terribly complicated to add this back in, but I wonder about the OTHER reasons that non-local variable assignment was removed from argument lists in the first place.

As for the utility of the feature, I'd like it but I can live without it. It does seem rather un-Ruby to have to declare locals and do the assignment when all you want is to set an instance variable...especially when you have a lot of instance variables.

Note also that for a trivial initialize, where the only line is a multiple-assignment to set instance variables, every initialize call pays the cost of creating an Array for the masgn (see my rejected request in https://bugs.ruby-lang.org/issues/6668).

def initialize(a, b, c, d, e)
  @a, @b, @c, @d, @e = a, b, c, d, e # creates transient array every time
end

#7 [ruby-core:55605] Updated by Anonymous over 3 years ago

@Matz: If define_attr_initialize is an option, then there is a question of named / ordered qualifier, either as:

define_attr_initialize :foo, :bar, as: :named
define_attr_initialize :baz, :quux, as: :ordered

or as (and I like this second option better):

attr_init_named foo: nil, bar: nil
attr_init_ordered :baz, :quux

Both of these would obviously stand for (using @sawa's notation):

def initialize( @baz, @quux, @foo: nil, @bar: nil )
      ...

Besides that, I feel that attr_reader, attr_writer, attr_accessor could use:

attr_reader :foo, :bar, init: :named
attr_reader :baz, :quux, init: :ordered

Which also brings to my mind, that now that we have named args firmly in place, following
syntactic flavors of Module#attr_... beg to exist:

attr_reader foo: 42, bar: 43  # specifying starting values explicitly

#8 [ruby-core:55615] Updated by Matthew Kerwin over 3 years ago

boris_stitnicky (Boris Stitnicky) wrote:

Which also brings to my mind, that now that we have named args firmly in place, following
syntactic flavors of Module#attr_... beg to exist:

attr_reader foo: 42, bar: 43  # specifying starting values explicitly

If you propose this as a feature, I will +1 it. Also I have some questions about it which probably should not pollute the current feature request.

#9 [ruby-core:55624] Updated by Anonymous over 3 years ago

If you propose this as a feature, I will +1 it. Also I have some questions about it which probably should not pollute the current feature request.

I have proposed is as #8564.

#10 [ruby-core:73529] Updated by Nobuyoshi Nakada 8 months ago

  • Description updated (diff)

#11 Updated by Nobuyoshi Nakada 3 months ago

  • Duplicated by Feature #12578: Instance Variables Assigned In parameters ( ala Crystal? ) added

#12 [ruby-core:76443] Updated by Benoit Daloze 2 months ago

Anonymous wrote:

@Matz: If define_attr_initialize is an option, then there is a question of named / ordered qualifier, either as:

define_attr_initialize :foo, :bar, as: :named
define_attr_initialize :baz, :quux, as: :ordered

You could have simply:

define_attr_initialize :baz, :quux, foo: nil, bar: nil

But this starts to look much like a macro to me.

One problem with the proposed define_attr_initialize is once some extra behavior needs to be added to initialize,
there is no choice but to desugar everything (write ivar assignments manually).
The original proposition does not have this issue.

IMHO many constructors usually need some custom behavior after some time,
and so paying the "cost" upfront of doing manual assignments is worth it in many cases.

#13 [ruby-core:76448] Updated by Rodrigo Rosenfeld Rosas 2 months ago

Even if define_attr_initialize would accept a block to enhance the initializer besides initializing instance variables it doesn't support default arguments. I'd certainly prefer the original proposal which I find more useful. It's not obvious what array.each(&:to_i) does either but people get used to it because it's handy. I think it's the same about this proposal although it's quite familiar for people using this feature in other languages like CoffeeScript and Crystal among others.

#14 [ruby-core:76449] Updated by Rodrigo Rosenfeld Rosas 2 months ago

Also it doesn't handle variable arguments, extra options that shouldn't be assigned to instance variables or &block.

Also available in: Atom PDF