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

Smooth Operator Overloading #284

Open
brainrake opened this issue Feb 27, 2013 · 17 comments
Open

Smooth Operator Overloading #284

brainrake opened this issue Feb 27, 2013 · 17 comments

Comments

@brainrake
Copy link

A long-time missing *script feature is operator overloading.
We can get close, e.g.

class Vector extends Array
  (arr) -> @push ...arr
  '+' : -> new Vector zipWith (+), @, it
a = new Vector [1 2]
b = new Vector [-1 6]
console.log a\+ b'+' a  # => [1, 10, constructor: function, +: function]

but even disregarding the ugly output (and 'class' and 'new'), it's far from perfect:

a\+b         # a['+b']  
fn a\+ b, c  # fn(a['+'](b, c))
a\+ b && c  # a['+'](b && c)

I propose adding the syntax:

a.+ b        # a['+'](b)
a.+b         # a['+'](b)
fn a.+ b, n  # fn(a['+'](b), n)
a.* b.+ c    # (a['*'](b))['+'](c)
a.< b        # a['<'](b)
a.< b.< c    # a['<'](b) && b['<'](c)
# etc.  'xor', 'and', 'or' stay unmodifide

I'm not so sure about these, especially the last one:

a.+= b      # a['+='](b)
fn a.++, b  # ($ref = fn(a, b)), a['++'](), $ref
fn --.a, b  # fn(a['--'](), b)

These are currently syntax errors, so it shouldn't conflict with anything. This syntax would clearly differentiate overloaded operators while still looking similar to the plain variety. The overloaded operators should have the same arity, precedence and bracket rules as the real ones.

@vendethiel
Copy link
Contributor

(Ref satyr/coco#60)

a\+ b and c compiles to
a['+'](b) && c;, not your code : and closes implicit calls.

@brainrake
Copy link
Author

thx, fixed example

@vendethiel
Copy link
Contributor

I suppose we could use doLiteral in lexer to change tag to LITERAL if last is dot. not sure if that's worth it, considering you have to implem these yourself anyway

@humanchimp
Copy link

neat idea!

@maxov
Copy link

maxov commented Mar 4, 2013

Maybe it's possible to just have some utility properties, that when defined, overload the operator without any need for more syntactic sugar(think python):

myObj =
    val: 5
    __plus: (that) -> that.val + @val

myObj + {val: 5}

Although, that would be a bit hard to implement at compile-time.

@brainrake
Copy link
Author

@gratimax, that approach actually adds an unnecessary renaming, hides the fact that overloading is happening, and requires runtime support.
obj.+ syntax overcomes these problems, and you can still use obj'+' or obj[\+] etc to perform a regular property lookup.

@maxov
Copy link

maxov commented Mar 4, 2013

@brainrape I guess you're right, then. +1

@craigyk
Copy link

craigyk commented Mar 4, 2013

Trying to gauge the temperature in the room:

I would love a way to overload array indexing and attribute access... actually way more than even arithmetic operators.

Not sure if mapping to something like python's getattr and getitem methods are the way to go, but maybe something similar?

@vendethiel
Copy link
Contributor

I would love a way to overload array indexing and attribute access

objects / length star / defineProperty :° ?

@craigyk
Copy link

craigyk commented Mar 4, 2013

@Nami-Doc

Not sure what you mean by that? Are you saying LiveScript already provides some ability to programmatically control attribute access? because as far as I can tell Javascript itself doesn't, and one would have to fake it. It would definitely be a lot slower than built in object attribute or array item access.

@vendethiel
Copy link
Contributor

class Object
  abc:~ -> "abc"

console.log (new Object)abc
# => "abc"

using Object.defineProperty

@craigyk
Copy link

craigyk commented Mar 4, 2013

@Nami-Doc

yeah, that's not the same thing. I mean programmatic access for intercepting attribute and indexing accesses as keys.

A heavily contrived Python example:

class Dog(object):
    def __init__(self,name):
        self.name = name
        self.tricks = {}
    def teach(self,name,trick):
        self.tricks[name] = trick
    def __getattr__(self,name):
        if name in self.tricks:
            return self.tricks[name].__get__(self)
        return lambda : self.name + " tilts head"

dog = Dog()
dog.teach("sit", lambda x: x.name + " sits")
dog.teach("speak", lambda x: x.name + ": Woof")

print dog.speak()  # "fido: Woof"
print dog.sit()       # "fido sits"
print dog.lay()      # "fido tilts head"

@vendethiel
Copy link
Contributor

Ah. Proxies then.

@craigyk
Copy link

craigyk commented Mar 4, 2013

@Nami-Doc

yeah, that looks about right... just wondering about how people feel about this in livescript since it can be thought of as a form of operator overloading. Though, come to think about it... can't see how implementing this as the Livescript level wouldn't slow all object accesses down, so....

@vendethiel
Copy link
Contributor

I don't see how we could do that in LS, tbh

@craigyk
Copy link

craigyk commented Mar 4, 2013

Yeah, can't see how it wouldn't be horribly slow without some kind of runtime support.

Hmm, looks like a proxy object is slated for Harmony though...

@brainrake
Copy link
Author

i wanted to keep it lightweight, that's why i didn't explore property access and indexing.
although indexing could work with

obj.[3]  #=> obj['[]'](3)

but that might conflict with livescript semiautovivification

there's also https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/get (and set)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants