"Robert Klemme" <bob.news / gmx.net> wrote

> Usually these conversions are documented as requirements for method
> parameters.  We could make them a bit more explicit without changing much
> especially not the power of Duck Typing.  Here's an idea:
>
> def silly_example(str.to_str, count.to_int)
>   # str and count are converted like in the example above
>   s = ""
>   count.times { s << str }
>   s
> end

I like this, and believe it can be generalized to be quite broadly useful.

I believe your signature tells a caller the following:
    silly_example takes 2 params, x and y
        (str and count, if you prefer; but see * below)
        x must support #to_str, y must support #to_int
    silly_example will use them as follows:
        str = x.to_str
        count = y.to_int
    silly_example will not have other access to x, y
    (*: since you did: str=str.to_str; count=count.to_int)

There are 3 main properties about this signature:
1. it reveals the duck-type of x, y as required methods
2. it reveals how those methods of x, y are used in the body
    str = x.to_str
    count = y.to_int
3. it saves typing: in particular, it has "no extra cost", since it
automatically binds str and count and this does not have to be repeated
within the body of f().

What do you think about the following generalization of your idea? It will
be a bit of a jump, so *please* consider it carefully:

    Allow a method signature to optionally indicate both
    the duck type of a parameter (what methods it should
    respond_to), as well as named variable bindings that
    indicate the usage of those respond_to methods within
    the method body.

In your:
    def silly_example (str.to_s, count.to_int)
"to_s" and "to_int" indicate duck-types, and str and count are the named
variables being bound for the method body.

Without suggesting the actual syntax, suppose /*type_pattern_with_vars*/
generalized this.
i.e. /*...*/ is some syntax for a pattern that binds some named variables
(like /.../ for regex) and that has optional type information (like c++
comments, hence optional :-)

Then, in the hypothetical example below:
def heat (x /*type_pattern_with_vars*/ )
if the /*...*/ somehow
    - referred to methods #min, #max, #cool, #explode
    - binds variables lo, hi, onHot, tooHot
Then type_pattern_with_vars *could* convey, via not-yet-determined syntax,
the following information:
- arg x must support #min, #max (#cool,#explode see below)
- x.min is used as the *lo* var in #heat
- x.max is used as the *hi* var in #heat
- x.cool is callable VIA the *onHot* var in #heat
- x.explode is callable VIA the *tooHot* var in #heat
[optionally: x itself is not otherwise directly accessible in #heat]

The signature is very informative, and it has all 3 properties of your
proposal:
1. it reveals the duck-type of x: #min,#max,#cool,#explode
2. it reveals how duck-type methods of x are used in the method
    lo = x.min;
    hi = x.max;
    onHot = x.method(:cool)
    tooHot = x.method(:explode)
3. it saves typing: in particular, it has "no extra cost", since it  binds
the above variables automatically, and this does not have to be repeated
within the body of #heat. If RDoc understood this, you'd have to write that
much less narrative explanation for your methods.

It is all still based on duck-ish respond_to? semantics rather than on
classes. It would *not* duplicate any work since the implementer of #heat
would *not* have to do any of the following:
    lo = x.min
    hi = x.max
    onHot = x.method(:cool)
    tooHot = x.method(:explode)
in #heat's body, as these variable bindings would be done by Ruby itself
just before the body of #heat. In fact, if the variable 'x' was somehow
ommitted, then these other variables would be the *only* handles on the
argument available within #heat i.e. a caller would know for sure that
x.cool could *only* be called via *onHot*. All I could do within the body of
#heat would be things like:
def heat (x /*...*/ ) # lo, hi, onHot, tooHot now bound
    temp = ... some stuff
    if (temp > lo && temp < hi) onHot.call()
    if (temp > hi) tooHot.call()

Any ideas about how to do /*...*/, any other comments or suggestions,
welcome!

p.s. This approach combines ideas of pattern matching with ideas of duck
typing.