Suggest an syntactic suger for `#call`

if a proc can be called like a function(i.e. with just parentheses and arguments, instead of a #call method):

p = ->obj.method(T,U)
def func(foo : T -> U)
  t = T.new(...)
  b = foo(t) # instead of foo.call(t)
  # ...
end

Shortening foo.call(t) to foo(t) make it more uniform (personally).This syntactic sugar is at most time comvenient, except only one ambiguration: If another method is also named foo, then foo(t) cannot differ between these calls. At that time, we can warn “ambigurous call with foo(t)”,and require programmer to specify it as a method and a proc call.if not specified, it refers to the method foo.

Ruby has a similar syntactic sugar .(),which is used like foo.(bar). it helps somehow,still different from a method call, I prefer using only one form of call.

3 Likes

Don’t we already have this with [ ]? Pretty sure you can call a proc like

->(a, b){ a + b}[1, 2]

Proc#[] is Ruby syntax, I tried to implement it in Crystal but I don’t think it works the same way – you can also get a pretty strange error message which might need to be put into an issue:

struct Proc
  {% begin %}
    def [](
      {% for i in T.size %}
        __arg{{i}} : {{T[i]}},
      {% end %}
    ) : R
      call(
        {% for i in T.size %}
          __arg{{i}},
        {% end %}
      )
    end
  {% end %}
end

echo = ->(text : String) { puts text }
echo["Hello world"]

Related: Alias Proc#[] to #call · Issue #11133 · crystal-lang/crystal · GitHub

This implementation doesn’t work because the macro expands statically where the generic arguments of Proc are not bound. Essentially, you cannot write a def that depends on the generic arguments.
But you can use the generic arguments as type restriction for the def’s parameters:

struct Proc(*T, R)
  def [](*args : *T) : R
    call(*args)
  end
end

echo = ->(text : String) { puts text }
echo["Hello world"]

(this is exactly the same signature as Proc#call btw.)

2 Likes