-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Infix function/method application #1429
Comments
This is something I like from haskell as well. I thought the choice of using the backtick was a little funky, though. It's an awfully hard character to reach for such a useful syntax. That particular character is already taken in coffeescript anyway. Also I didn't understand why the function had to be wrapped in two backticks, seeing as the function name would be recognizable as such without having to be wrapped in anything. If we did this in coffeescript, I think it would be nice to smooth over those implementation details. Maybe something silly like prefixing the function with the
|
|
I was thinking about this today, and I figured it might be possible to distinguish between prefix and infix by only allowing infix functions to be used in an infixy way, but then the problem is how do you distinguish between the two? I like benekastah's idea of prefixing it with something, but the question is what? We're kind of restricted by the ASCII charset. |
I +1 this request, as long as one can find a nice syntax that isn't already taken by the language, or that doesn't make the parser even more ambiguous. PS.: The grammar could be:
Of course, this is not as lightweight as one could wish for. If infix expressions (those that evaluate to a function that can be applied to the lhs and rhs), we could just have I'm not too keen on the infix notation for method invocation (the All in all, I think this would really make CoffeeScript a lot more expressive :3 |
+∞. Pinging @jashkenas - any chance to get your feedback on that? Also, just a thought: what about allowing (pre|suff)ix-less special character operators? Its problematic because JavaScript only allows alpha-numerics and $/_ in identifiers, but maybe it can be done using some "magic object" to hold the operators as properties - e.g. |
I dunno. Why would you want to limit yourself to only having one of the arguments on the LHS? Why would this be undesirable?
Probably, in most cases where you have actual objects, you won't need this in any case:
All of the examples in this thread are for operators ... that are already real operators. How about some examples of how this would be helpful for real code? In the meantime, closing as a |
@jashkenas Well, it's not about operators per-se but the readability (natural flow, if you will). You're right that objects solve part of this problem, but it's not really practical to have all operations on objects, all the more given the high use of functional idioms in JavaScript (and I believe more so in CoffeeScript, from people not coming from strict OO-only languages). So, with objects you have a single dispatching where the single item on the LHS is the most important thing in the equation, and this is still restrictive. For example: var slice = () -> [].slice.call.apply [].slice, arguments
var sequence = { 0: 1, 1: 2, length: 2 } With usual message passing for OO idioms, this looks okay sequence.__proto__ = Array.prototype
sequence.slice 1 # => [2] With the usual function application idioms, the application looks awkward slice sequence, 1 # => [2] With the ability to define any function as infix, you can get the same natural reading from idiomatic OO dispatching, but without the need to monkey-patch the object (so, less overhead and a lot safer) sequence `slice` 1 # => [2] This is all good for the usual single-dispatching from OO-ish idioms. But indeed functional idioms allow people to do multiple dispatching, as it's not apparent who are the main players in a function application. Magpie solves this nicely by allowing you to define arbitrary number of arguments to come before the function's identifier, and arbitrary to come after the function's identifier. def (this is Person, action is Verb) to (predicate is String)
print("Let it be know that " + this name + action + " to " + predicate)
end
Alan went to "the church"
# => "Let it be know that Alan went to the church" ( You can read more about Magpie's handling of function application here: http://magpie.stuffwithstuff.com/calls.html ) |
...just some possible infix application. # string comparison
like = (strOne, strTwo) -> strOne.toLowerCase() is strTwo.toLowerCase()
a = 'some string'
b = 'SOME string'
if a `like` b then do_something()
# something more useful, class implement
implements = (base, props) -> base::[key] = value for value, key in props
class UsefulStuff
method1: (does) -> things()
method2: (is) -> @extremely_useful
someProps =
method3: (also) -> a_neat method
importantNumber: 123
UsefulStuff `implements` someProps
(new UsefulStuff).importantNumber is 123 # true ...becomes... // comparison
if(like(a, b)) do_something();
// class
function UsefulStuff(){ /*etc*/ }
implements(UsefulStuff, someProps); In my humble opinion, |
@jashkenas I'm not familiar with the Haskell style, but it seems similar to the F# pipelining operator. Its really useful for stuff like filtering, sorting, etc. on a collection/array. Here's one example of how this is used in F#:
This converts the sequence of cards into a tuple containing the card and a random number, sorts by the random number, gets the second element of each tuple (converting it back into a sequence of cards), gets the first 10 cards, and converts it to a list. It's equivalent to the following F# code:
As you can see, the first way is much more readable. (In case you get confused when reading this code, F# does not need to seperate the arguments for functions.) |
Why I personally find this feature very exciting:
IMHO having that feature, in combination with CoffeeScript's syntax, would make CoffeeScript one of the best languages (that I know of) for DSLs, fluent-style/literal programming and customization by the developer. |
Very sad that this issue is 2 years old and still not implemented. One more really regular usage is options = ^defaults extendWith options or {} It's so beautiful! Here above example with inline object instead of options = ^(
data: "id=1"
url: "http://"
) extendWith options or {} I think full syntax for infix should be So here valid examples ^variable functionName param1, param2
^functionName(params) functionName param1, param2
^object.field functionName param1, param2
^object.method(params) functionName param1, param2
^(variable + 1) functionName param1, param2
^(
field1: 1
field2: 2
) functionName param1, param2 |
Sorry, I forgot about xor operator options = :defaults extendWith options or {} |
@michaelficarra Care to share why reopened - still applicable? The examples here seem to come from land of custom DSLs, and I think that CoffeeScript can be a target for these but probably shouldn't force them onto the general public. This goes along requests for macros, operator overloading etc. - with great power comes great mess (C). |
@xixixao: I'm not sure why we re-opened it. I am personally in favour of the proposal. But you're right, this just wouldn't be consistent with other, similar design decisions we've made. |
Then let's put it down for now. |
It will be nice to have infix function/method application in coffeescript, just like Haskell does. This would improve the look of EDSLs in coffeescript. Here is an example of infix function application:
Infix method application could be implemented like this:
Haskell also allows infix expressions like
a 'foo x + 1, y' b # foo(x + 1,y,a,b);
and function operators are not restricted by its aritya 'foo' b, x, y # foo(a,b,x,y)
.The text was updated successfully, but these errors were encountered: