Issue #9428 has been updated by Matthew Kerwin.


 On 20 January 2014 10:41, <tom / tomwardrop.com> wrote:
 
 > Issue #9428 has been updated by Tom Wardrop.
 >
 >
 > 1. I know you said you're not a fan of allowing expression when assigning
 > default values to optional parameters, but the point about aesthetics
 > applies equally to them also.
 >
 
 That's partly why I'm not a fan.  If I could think of a valid, useful
 alternative I would strongly suggest it.  I know it wouldn't be adopted
 (backwards compatibility, if nothing else) but I'd propose it anyway.  The
 best I can come up with is another special method, along the lines of
 method_given?, perhaps:
 
   def foo bar, baz=?  # no idea what syntax to propose here
     baz = 42 unless argument_given? :baz
   end
 
 It's not great, obviously, but it removes arbitrary code from the 'def'
 line.
 
 
 
 > 1. The rule is relatively simple. The first identifier (lvar/method)
 > encountered is automatically assigned the value of the argument passed to
 > the method or proc. That's the rule, the first identifier (valid variable
 > name) is assigned the argument value. If you want to refer to `self.id`,
 > you must use `self.id` to disambiguate as you would have to in many other
 > scenario's in Ruby. In the example you highlighted `def foo( arg.to_i )`,
 > the identifier `arg` is encountered and automatically assigned the argument
 > value before the expression continues execution.
 >
 
 "First encountered" in regular left-to-right parsing order?
 
   def foo( a[b] )
 #=>
   def foo a
     a = a[b]
   end
 
 ?
 
 
 
 > 1. The same problem exists for expressions used as default values for
 > optional arguments.  Debugging is the same for each. If it's not clear
 > where the error occurred, one could always temporarily break the argument
 > definitions over multiple lines while debugging. I don't think debugging
 > would be any worse than debugging a long method chain like `Hash[var.select
 > { |v| #bleh }.map { |v| # blah }]`. I therefore don't think debugability
 > can be used against this proposal.
 >
 
 I agree that existing long/complex lines are hard to debug.  But why add
 the opportunity for more such lines?  Especially in a place that is
 traditionally free from such concerns?  With my background as a C
 programmer I instinctively see the 'def' line as free from execution; it's
 a definition, something that informs the interpreter and the human reader
 about the nature of the program/data/etc.  I would be surprised if I
 started seeing runtime exceptions raised from these traditionally
 compile-time-only lines.
 
 Again, I know it's already possible to achieve these errors using optional
 args, but I concede that as a necessary evil in the absence of an
 alternative.  And, since we're stuck with them, I prefer a culture of
 promoting the least amount of executable code possible in that line; thus
 some of my opposition to this proposal.
 
 
 
 > 1. Technically, for optional arguments, you can have an expression for
 > when an argument is given, and an expression for when an argument is
 > optional. It remains consistent in this respect.
 >
 >     `def foo(id.to_i = config[:default_id])`
 
 
 This introduces some amount of confusion. Which of the following is
 equivalent?
 
   id = id.to_i // id = config[:default_id]
 
 or:
 
   id = id.to_i // id = config[:default_id].to_i
 
 Either way, this is very confusing when, anywhere else in a Ruby script, it
 would mean:
 
   id.to_i=( config[:default_id] )
 
 
 -- 
   Matthew Kerwin
   http://matthew.kerwin.net.au/

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

* 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/