Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow methods to match on block argument structures. #82

Open
faultyserver opened this issue Dec 16, 2017 · 1 comment
Open

Allow methods to match on block argument structures. #82

faultyserver opened this issue Dec 16, 2017 · 1 comment
Labels
feature-request Any request for a new feature of the language. Includes both syntax and library features. rfc A request for comments from the community syntax Any issue relating to the syntax of Myst.

Comments

@faultyserver
Copy link
Member

In Ruby, blocks are special-cased with how their parameters are matched. Unlike any other method in Ruby, blocks can be given more or fewer arguments than they are defined to accept, and the interpreter will be okay with it:

[1, 2, 3].each{ |a, b, c| puts a }
[1, 2, 3].each{ puts "hi" }

This is really more like javascript, and while I've definitely used/abused this feature before, I don't particularly like its implicit nature from a design perspective.

I would prefer allowing methods to match the structure of the block argument they are given, and define different clauses accordingly. Crystal supports this in a way that's fairly clean, but more verbose and restrictive than I think I would like:

def transform_int(start : Int32, &block : Int32 -> Int32)
  result = yield start
  result * 2
end

transform_int(3) { |x| x + 2 } #=> 10
transform_int(3) { |x| "foo" } # Error: expected block to return Int32, not String

In #57, I've already started describing method signatures using a more terse version of this syntax. Expanded into an actual method definition, it might looks something like this:

def map(&block(e))
  [1, 2, 3].each do |e|
    block(e)
  end
end

def map(&block(e, i))
  [1, 2, 3].each_with_index do |e, i|
    block(e, i)
  end
end

This would define two different clauses that each expect a different block structure, one accepting an index parameter, and the other not. Usage wise, this wouldn't look any different from Ruby:

map{ |e| IO.puts(e) }
map{ |e, i| IO.puts(e, i) }

Maybe this is unnecessary or unhelpful, but I've been thinking about how to more explicitly implement the variadic matching of Ruby blocks, and this is the best I've come up with.

@faultyserver faultyserver added feature-request Any request for a new feature of the language. Includes both syntax and library features. semantics Generic label for semantics issues. All semantics issues should have this tag. syntax Any issue relating to the syntax of Myst. labels Dec 16, 2017
@faultyserver
Copy link
Member Author

A concern with this is how it would affect block parameters that are really captured functions with multiple clauses. Should it match if at least one of those clauses matches? Should it only allow one clause? Can the pattern define multiple clauses to match?

@faultyserver faultyserver added the rfc A request for comments from the community label Dec 25, 2017
@faultyserver faultyserver removed the semantics Generic label for semantics issues. All semantics issues should have this tag. label Jan 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Any request for a new feature of the language. Includes both syntax and library features. rfc A request for comments from the community syntax Any issue relating to the syntax of Myst.
Projects
None yet
Development

No branches or pull requests

1 participant