Issue #9428 has been updated by Tom Wardrop.


> I do not see why the person or machine that reads the first line of method's definition needs to know how the arguments will be post-processed before being further post-processed

Semantically, it just seems more appropriate to define the argument transformation as part of the method definition. It's common to have the first line or two of a method be argument transformation, the point of which is to check and coerce the arguments into their expected form. The actual logic of the method normally just uses that argument variable without ever reassigning it. It wouldn't likely be "further processed" (i.e reassigned) within the method body as you suggest. Where the argument is only used once within the method, you can do the transformation inline; it'd be unnecessary to do it in the method signature unless you wanted to for documentation reasons.

It's in some respects, you could consider it type hinting for a dynamic language. While statically typed languages would have a type hint., in dynamically typed languages, it's not uncommon for one to check and coerce the argument into something expected.

----------------------------------------
Feature #9428: Inline argument expressions and re-assignment
https://bugs.ruby-lang.org/issues/9428#change-44460

* Author: Tom Wardrop
* Status: Rejected
* Priority: Normal
* Assignee: 
* Category: core
* Target version: 
----------------------------------------
Just a random idea. Currently, Ruby allows you to use any arbitrary expression for setting default values for arguments, which can be really convenient and makes for clear code, especially handy for documentation, etc. For example:

    def fetch(id, cache = config[:cache])
      # bleh
    end

In the same vein, as well as setting a default value using an arbitrary expression, it's not uncommon to *post-process* an argument, some common examples include:

    arg = arg.upcase
    arg = arg.to_sym
    arg = arg.dup

It would be rather nice in my opinion to be able to do this inline when defining the argument:

    def fetch(id.to_i, cache = config[:cache])
      # bleh
    end

This works well where the argument is the receiver of the method call, but what if you wanted to do `Integer(id)` in the above example instead of using String#to_i? There are two options. One could either fallback to processing the argument within the method/block body, or, you could make the implementation a little bit clever by using inferencing.

Ruby could auto-assign the passed argument to the first variable encountered in the expression. So in the following example, as soon as the virtual machine encounters `id`, it recognises it as a variable and assigns the argument value before continuing. When encountering subsequent variables, Ruby would take the usual action and look for a corresponding method in `self` before throwing an error. You can always disambiguate by qualifying the receiver, e.g. `self.id`

    def fetch(Integer(id), cache = config[:cache])
      # bleh
    end

Whatever the result of the expression, it's assigned as the final argument value. So in the case of `id.to_i`, the argument name of `id` is inferred. `id` is set to the supplied argument for the duration of the expression. The result of the expression is then re-assigned as the value of `id`. This technically allows expressions of arbitrary complexity, but like all things in Ruby, with great power comes great responsibility. One must use common sense when deciding whether to manipulate the argument inline, or within the method body. As long as the expression is of reasonable length and complexity, readability remains perfectly reasonable.

Interested to get some thoughts and opinions on this one. I sense the potential for controversy :)




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