Closed slavah closed 12 years ago
'_' is a wildcard which means "I don't care what the value is". It just so happens that a single underscore will match anything, though what its really doing is just checking the first argument and discarding it (it matches undefined also).
Though I do see your point. Perhaps there should be a special case for a single underscore. The only reason you would ever use it is as a catch all, so it makes sense that you could.
I have been thinking about adding rest arguments (the ellipsis in arrays and objects, but applied to arguments). I think this is ultimately the real solution. In that case, if you wanted a catch all that would also collect the arguments you would do:
pattern({
// A single underscore discards all arguments
'_': function () { ... },
// A rest argument collects all arguments
'args...': function (args) { ... }
});
Thanks for your comments Nate.
I was thinking about changing "" at some point to just work as wildcards " * ". I really can not come up with example when someone would want to use only and only "Drop All and Match All" semantics of " " and not be satisfied with more relaxed version of "Match All".
Or do you have something else in mind in regards to ' _ ' semantics?
Of course 'args...' works nicely as well, but its an extra syntactic rule. And in case it's only for this usage scenario, doesn't worse IMO to have separate rules.
But if to go into route of implementing extra rules then maybe what we really want is to augment "..." to full semantics of "*" ? Allow it to be first class pattern - expression, which can be applied to others or by itself to be present in patterns.
Then we would be able to do something like this: '[..., "particular_Item", xs...] : function(xs) {} '[x..., "particular_Item", xs...] : function(x, xs) {} '[..., "particular_Item", ...] : function() { return "particular_Item" }
and this "args..." : function(allArguments){} - application
Might be thought a bit too complex? What do you think?
I don't really want to change the semantics of . It's already established what it means in other languages that have pattern matching. It's only a quirk of the way you can call javascript functions that matches all (ie. you can call a js function with any number of args, any that aren't passed are just undefined, and any extras are ignored. The underscore matches undefined, so it will match on the first argument if an argument is there or not).
Do you have good use cases for having multiple "..."s within a series? I could see adding it if there is a clear, terse way to work around all the edge cases (multiple "..." in a row, splitting unequally, etc). It isn't present in coffee script, and I think that's for a reason.
With the current grammar, it wouldn't require any extra work to add rest arguments. An argument list could use arrayRestPatterns
instead of patterns
since arguments are just an array without the '[]'.
I totally understand your argument of underscore semantics already being defined in many languages. But as you mentioned, JavaScript has it argument object, and i was thinking to modify " _ " to particularly fit this case, "arguments" object can be viewed and used as environmental argument stack.
I probably missing something here. Is there any scenario do you have in mind, where one would have specifically to use " _ " and cant replace it in every case with proposed by you "args..." ?
In regards to "...". I did not give it much of thought really, i just assumed it being dual to existing rules. If we already have: '[x, ..., y]': function (x, y) { ... }, kinda begs for symmetry to have: '[..., obj@{className:'test',... }, ...]': function (obj) { ... }, While first example clearly semantical, second already existential (duality) - have to have knowledge about structure, and items.
From type point of view - typing of array in this way similar to '[1, 2, 3]': function () { ... }. I don't see it being otherwise, in meaning '[..., x, ...]': function (obj) { ... } - is a wrong pattern (can not be a function) In case it's being a literal - "...", '...' there are no situation where we would have more then single meaning.
Scenarios, well for my particular case, i do match against inheritance chain to see if object is of Parent type. Since child objects hides parent tag (let say className property) i have to match against chain. I cant assign type to array right now in declarative way by occurrence of particular item in it.
I might be actually mixing concerns with typing here, but let say in reactive scenarios you type array by occurrence of item in it for example throttling - [mouseMove, mouseMove, mouseMove, ..., mouseClick]. Its not really a showstopper in any way, just a thought :)
What are your thoughts on this?
As far as "" goes, I think it helps express intent more (the arguments don't matter vs I want all the arguments). More than that though, I think having "..." for arguments opens up being able to use "" more strictly. Whereas right now the pattern "a, b, " will match even if you only pass two arguments, I could see the advantage of "" meaning that while I don't care what the value is, a value needs to have been passed. So "a, b, _" would only match if 3 arguments were explicitly passed.
I don't quite follow your inheritance example and what it has to do with [..., x, ...]. Maybe I don't get what this pattern really does. Is it supposed to say "I want the middle value", or is it saying "I want a value that matches this pattern but I don't care where it is in the array"? I don't think the former is that useful, but I think the latter is. For the latter, maybe we just need a different way of expressing "contains". I think it gets confusing because it seems like you should be able to do [a..., x, b...], but that doesn't really make sense to me in relation to contains. I think its best to think of "..." as a "fill" more than a glob. Also, it doesn't make much sense with objects (maybe object matching shouldn't be strict, though?).
Also, to throw this out there, I plan on doing a custom extractor syntax, so you can register extractors and use them like types (maybe using a dollar or something):
matches.extractors.Email = function (val, pass, fail) {
// Parse email string
return pass({ name ..., domain: ... });
}
pattern({
"$Email{domain: x, ...}": function (x) { ... {
});
Maybe something like this will be better suited for what you are wanting to do?
I see your point. I would like “” to be more strict as well. I did not realize that “a,b,” would match even 2 arguments.
Sorry if my example was confusing – it is the other way around actually :) I was saying that [..., x, ...] is the case which should never work! since it maps 1 variable x to many possible outcomes. And it should impossible to represent such case in pattern matching rules either. Same goes for [a..., x, b...] pattern.
(definitions of examples for shortness) Example1: [x, …, y] Example2: […, {field:val, …},…]
I was saying, since we already have defined pattern [x, …, y] – it begs for a dual pattern, which would be Example2.
In Example1 , X and Y are of Any type(we don't know a type of them, we just match on position). In Example2, object {field:val, …} is known to programmer “existing type” (since he declaratively defined it in pattern).
Example was to tag arrays by the type of element in it. In Example1 all we have x:any and y:any defined by their respective positions, therefore we only can do deconstruction of array (extract elements from it, x,y by their position), but we cannot use those elements (of type 'any') to do method dispatch. To type match on array (and to do dispatch) we need {field1:val1}, the objects of known, existing(known) type to programmer, hence Example2.
Example: ‘[x, …,y]’: function(x,y) {console.log(‘we have now x and y’); ‘arr@[.., {mouseMoves:true, …}, …]’ : function (mouseMoves) { console.log (‘user moved mouse and we have his moves coordinates’’);} ‘arr@[..,{mouseClicks:true, …}, …]’ : function (mouseClicks) { console.log (‘user clicks, and we have his click coordinates’);}
Does it make sense to you? Essentially I was saying it would give ability to type dispatch on arrays. Of course its a poor man typing, since we don't have way to say that match on array which contains only and only particular type. '[{mouseMove}...]': functions(onlyMouseMoves) {}
In regards to extractors. Do you see them in a way that we can use it as a type, i.e. ‘{x: true, y: $Email, …}’ : function(x, email) {}
So you are wanting to match on an array that only contains elements that match the given pattern?
I think that could be powerful, though slow since you would have to traverse the whole array each time. You could do some cool things with it like:
pattern({
'[{name: x, ...}...]': function (x) {
// x is now an array that contains only the names of the objects
}
});
We're kind of getting into ellipsis overload here (I like the above more than ..., expression, ...), but I like the idea. It's definitely something to put on the list.
Yes one of the possibilities moving "..." to first class expression would give us.
I was playing last couple days with matches.js and in case i would be able to get the syntax/semantics i was talking about to type arrays in safe and declarative way, you will be able to take a look at it in my repo :)
Thanks!
Cool! Look forward to seeing what you do. Be sure to checkout the latest master as it uses a new parser.
Closing this as the issue with "_" has been resolved with the addition of rest arguments. Refer to issue #7 for rest expressions.
HI, Is there a reason why '_' does not provide arguments to the target function?
Example of usage scenario: To log wrong arguments:
"_" : function() { me.logger.log("Wrong arguments provided", slice.call(arguments)); }
Or do i miss some other option to capture all provided arguments?
Thanks.