Issue #15192 has been updated by TylerRick (Tyler Rick).


## Same feature in TypeScript

It's worth mentioning that other languages have a shortcut for assignment var assignment directly from constructor parameters. So it seems especially painful that Ruby, despite being *so* beautifully elegant and succinct in *other* areas, still has no such shortcut for this.

One of those other languages (CoffeeScript) is dead now, but TypeScript remains *very* much alive and allows you to write this ([REPL](https://www.typescriptlang.org/play?#code/MYGwhgzhAEBiD29oG8BQ0PWPAdhALgE4Cuw+8hAFAA7EBGIAlsNGAFw7EC2dApoQBpotBs2h0O3PoOGFGANzD5eWST34BKFOkwBfVPqA)):
```js
class Foo {
    constructor(public a:number, public b:number, private c:number) {
    }
}
```
instead of this boilerplate:
```js
class Foo {
    constructor(a, b, c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }
}
```

(The `public`/`private` access modifiers actually disappear in the transpiled JavaScript code because it's only the TypeScript compiler that enforces those access modifiers, and it does so at *compile* time rather than at run time.)

Further reading:
- https://www.typescriptlang.org/docs/handbook/2/classes.html#parameter-properties
- https://basarat.gitbook.io/typescript/future-javascript/classes#define-using-constructor
- https://kendaleiv.com/typescript-constructor-assignment-public-and-private-keywords/

I actually wouldn't mind being able to use `public`/`private` modifiers on instance var parameters in Ruby, too, but if we did, I would suggest making that be an additional *optional* shortcut (for defining *accessor methods* for those instance vars) that builds on top of the instance var assignment parameter syntax described here. (See more detailed proposal in #__.) Accessors are more of a secondary concern to me: we can already define accessors *pretty* succinctly with `attr_accessor` and friends. The bigger pain point that I'm much more interested in having a succinct shortcut for is *instance var assignment* in constructors. 



## `initialize(@a, @b, @c)` syntax

jsc (Justin Collins) wrote in #note-12:
> jjyr (Jinyang Jiang) wrote:
> > I am surprised this syntax has been repeatedly requested and rejected since 7 years ago.
> 
> ...
> 
> As someone who has been writing Ruby for over 10 years, this syntax is exactly that I would like.
> 
> I grow really tired of writing
> 
> ~~~ruby
> def initialize(a, b, c)
>   @a = a
>   @b = b
>   @c = c
> end
> ~~~
> 
> This would be perfect:
> ~~~ruby
> def initialize(@a, @b, @c)
> end
> ~~~
> 
> I'm a little bit sad Matz is against this syntax, as it seems so natural to me.


Me too!! I've been writing Ruby for over 15 years, and this syntax seems like the most obvious, simple, natural, clear, unsurprising, and Ruby-like.

I believe it would be readily understood by any Rubyist without any explanation required.

Even if you saw it for the first time, I can't think of any way you could *miss* or *misinterpret* its meaning:
- since `@a` is in the same position as a local variable `a` would normally be, it seems abundantly clear that instead of assigning to a local variable, we're just assigning to the variable `@a` instead
- and of course you can reference the `@a` variable in the constructor *body*, too, exactly the same as you could with a local variable `a` passed as an argument.




## A workaround pattern

In the meantime, I've taken to defining my constructor and list of public accessors (if any) like this:

```ruby
    attr_reader \
            :a, :b
    def new( a,  b)
            @a, @b =
             a,  b
    end
```

... which is *still* horrendously boilerplatey and ugly, and probably most of you will hate  but by lining up the duplicated symbols into a table of columns, I like that I can at least more easily *see* the ugly duplication and *cross-check* that I've spelled them all correctly and handled them all consistently. :shrug:


## Please??

Almost every time I write a new class in Ruby, I wish for this feature and wonder if we'll ever get it. Can we please?

----------------------------------------
Feature #15192: Introduce a new "shortcut assigning" syntax to convenient setup instance variables
https://bugs.ruby-lang.org/issues/15192#change-92393

* Author: jjyr (Jinyang Jiang)
* Status: Open
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
----------------------------------------
Motivation:

Introduce a new syntax for convenient setup instance variables for objects.

The problem:

Currently, setup instance variables in Ruby is too verbose. 
Basically, we need to write the meaningless assigning code again and again to assign variables

``` ruby
class Person
  def initialize(name:, age:, gender:, country:)
    @name = name
    @age = age
    @gender = gender
    @country = country
  end
end


# we can use Struct to avoiding this

Person = Struct.new(:name, :age, :gender, :country, keyword_init: true)

# let's see a real-world case, which can't use Struct to describe an initializing process, from https://github.com/ciri-ethereum/ciri/blob/748985ccf7a620a2e480706a5a6b38f56409d487/lib/ciri/devp2p/server.rb#L54
# Because we want to do something more than just assigning instance variables

class Server
      def initialize(private_key:, protocol_manage:, bootstrap_nodes: [],
                     node_name: 'Ciri', tcp_host: '127.0.0.1', tcp_port: 33033)
        @private_key = private_key
        @node_name = node_name
        @bootstrap_nodes = bootstrap_nodes
        @protocol_manage = protocol_manage
        server_node_id = NodeID.new(@private_key)
        caps = [Cap.new(name: 'eth', version: 63)]
        @handshake = ProtocolHandshake.new(version: BASE_PROTOCOL_VERSION, name: @node_name, id: server_node_id.id, caps: caps)
        @tcp_host = tcp_host
        @tcp_port = tcp_port
        @dial = Dial.new(bootstrap_nodes: bootstrap_nodes, private_key: private_key, handshake: @handshake)
        @network_state = NetworkState.new(protocol_manage)
        @dial_scheduler = DialScheduler.new(@network_state, @dial)
      end
end


# Introduce a new "shortcut assigning" syntax for convenient setup

class Person
  # use @ prefix to describe instance variables.
  def initialize(@name:, @age:, @gender:, @country:)
  end

  # equal to
  def initialize2(name:, age:, gender:, country:)
    @name = name
    @age = age
    @gender = gender
    @country = country
  end

  # it should also work on position style arguments
  def initialize2(@name, @age, @gender, @country)
  end
end

# Our real-world case can be rewritten as below
class Server
      def initialize(@private_key:, @protocol_manage:, @bootstrap_nodes: [],
                     @node_name: 'Ciri', @tcp_host: '127.0.0.1', @tcp_port: 33033)
        server_node_id = NodeID.new(@private_key)
        caps = [Cap.new(name: 'eth', version: 63)]
        @handshake = ProtocolHandshake.new(version: BASE_PROTOCOL_VERSION, name: @node_name, id: server_node_id.id, caps: caps)
        @dial = Dial.new(bootstrap_nodes: @bootstrap_nodes, private_key: @private_key, handshake: @handshake)
        @network_state = NetworkState.new(@protocol_manage)
        @dial_scheduler = DialScheduler.new(@network_state, @dial)
      end
end

# consider to keep consistency, this "shortcut assigning" syntax should work for non-initialize methods
class Foo
  def bar(@still_works)
    p @still_works
  end
end
```



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>