wurstscript / WurstScript

Programming language and toolkit to create Warcraft III Maps
https://wurstlang.org
Apache License 2.0
224 stars 30 forks source link

More Operator Overloading #297

Open eeeey opened 10 years ago

eeeey commented 10 years ago

Hi there,

I would like to suggest new language features, namely more operator overloading. It would be nice to be able to overload [] and () operators to create array-like access to data structures and functors. Examples:

package First
    class MyList<T>
        // Some stuff
        function operator[](int index) returns T
            return getEntry(index).elem

    class MyFunctor
        private real memory = 0.0

        function operator()(real r1, real r2) returns real
            memory += r1*r2
            return memory // Just an example

    init
        // Usage operator[]
        MyList<int> list = new MyList<int>()
        print(list[0].toString())

        // Usage operator()
        MyFunctor func = new MyFunctor()
        print(func(2.0, 3.0).toString()) // Displays 6
        print(func(2.0, 3.0).toString()) // Displays 12
        print(func(2.0, 3.0).toString()) // Displays 18 
endpackage

And keep the good work :)

Frotty commented 10 years ago

We thought about that some time ago. While I think [] might have some purposes, the () example only makes the code less readable and harder to understand. (a lot into the Nes' Jass Faction)

Someone else looking at this will have no idea what is actually happing since there is no jumptodecl for [] and ().

Granted, this is the same for the arithmetic operators, but I havn't seen it misused yet and it makes using vector much more easy to read and write.

However writing:

list.get(0).toString()

instead of

list[0].toString()

Doesn't seem as an improvement to me..

Also, Lists are mostly for looping. If you want direct access to values other datatypes are probably faster (like arrays, duh).

eeeey commented 10 years ago

Well, the list was more an abstract example. It would be good to have those operators in general, because it really depends on the data structure if those are feasable. Example:

package First
    import HashMap

    init
        HashMap<int, int> map = new HashMap<int, int>()
        map.put(0, map.get(0) + 5)
        map[0] += 5 // Much nicer and readable, right?
endpackage

Or consider a Matrix class where you want to have 2d indexing:

Matrix<int> mat = new Matrix<int>(5, 5) // Create 5x5 Matrix

// Which one is more readable:
mat.set(2, 5, mat.get(2, 5) + 8) // this one
mat[2][5] += 8 // or this one?

// or alternately C# Style:
mat[2, 5] += 8

So actually an operator[] would improve readability a lot more than the +-*/ operators do already. The jumptodecl has the same problem with those aritmetic operators, so thats not really an argument.

Nes' coding is so unreadable because of his excessive macro/module abuse and abuses like faking this pointers and so on. Plus sacrificing everything for speed.

I don't think those operators would lead programmers into this direction. It is always the responsibility of the programmer to make his functions do the "intuitive correct" thing. You can also abuse the arithmetic operators to do completly unintuitive things. Or any other function which has name "doA" but does B instead. Such problems simply can't be avoided by any language, and therefore shouldn't IMHO.

There will be always bad styled code, but this shouldn't limit the capabilities of a language IMO.

peq commented 10 years ago

Overloading [] would be nice, but overloading function application is just too confusing, in my opinion. Jumping to declaration is not a big problem, it could work the same for [] as it does for the currently overloaded operators.

eeeey commented 10 years ago

Ok, I guess you are right, operator[] should be enough.

It would just be cool if you could make it so that it can take an arbitrary number of arguments. So that you can for example write for a matrix class something like:

class Matrix<T>
    function operator[](int index) returns T
        skip // for linear indexing of the matrix
    function operator[](int row, int col) returns T
        skip // for 2d indexing of the matrix

init
    Matrix<int> mat = new Matrix<int>(3, 3)

    print(mat[5].toString()) // Access to the linear index 5
    print(mat[2, 3].toString()) // Access to row 2, column 3

Because this way the need of a proxy class to allow 2d-indexing could be avoided.

Cokemonkey11 commented 8 years ago

I'm not a fan of overloading function declaration, but I do like [].

Can we have overloading for <, >, <=, >= operators?

There is a fairly well-defined convention for comparing tuples, for example:

public function vec2.op_lt(vec2 other) returns boolean
    return (this.x < other.x) or (this.x == other.x and this.y < other.y)
peq commented 8 years ago

I think for the comparison operator it would be nicer to link the operators to a comparable interface or type-class. It would feel strange to overload <, >, <=, >= and == with 5 separate functions.

Defining < for vec2 does not make sense in my opinion, because there is no default linear order. Some people might expect that the comparison is done by length instead of lexicographically.

Cokemonkey11 commented 8 years ago

I think for the comparison operator it would be nicer to link the operators to a comparable interface or type-class. It would feel strange to overload <, >, <=, >= and == with 5 separate functions.

Yes, I would be happy with that as well. Seems like more work for you though :P

Defining < for vec2 does not make sense in my opinion, because there is no default linear order. Some people might expect that the comparison is done by length instead of lexicographically.

vec2 always has length of 2. For a template type like pair<T, T>, I agree with you, but for vectors of numbers I think the convention I mentioned above is really quite standard.

Python:

>>> (1, 2) < (1, 3)
True
>>> (3, 1) < (2, 5000)
False
>>> (1, 2) < (2, 1)
True

I did think of one exception - partial ordering https://en.wikipedia.org/wiki/Vector_clock#Partial_ordering_property

I think it makes sense for vec2 to have at least some default ordering.

peq commented 8 years ago

A Python tuple is something more generic. You can use tuples for many different things, so there will be some cases where lexicographical ordering makes sense.

But vec2 is really supposed to be a vector with 2 dimensions and there is no standard ordering for this domain. I also cannot think of an example where you want to ask a question like: "Is the position of unit A less than the position of unit B?". Comparing positions like this just does not make sense.

Cokemonkey11 commented 8 years ago

Okay, I think that's fair. I argue that vec2 isn't necessarily for representing location of unit, but I can see that for the typical use case, having an ordering could do more harm than good.