magic-lang / rock

ooc compiler written in ooc
http://ooc-lang.org/
MIT License
14 stars 4 forks source link

Add count property/variable/method on enums #65

Closed marcusnaslund closed 8 years ago

marcusnaslund commented 8 years ago

Here's an idea:

myEnum: enum {
  AA
  BB
  CC
}

myEnum count toString() println()

should print 3. Not sure if this is possible or easy, but certainly useful.

alexnask commented 8 years ago

This should be fairly trivial.
In fact, since EnumDecl is a child of TypeDecl, this could probably be achieved by just adding a count static Int variable when resolving.

I don't know what the correct behavior should be if the user tries to define a count element in the enum though. Probably an error?

marcusnaslund commented 8 years ago

Sounds right.

But maybe restricting enums to not contain any count element is bad...

alexnask commented 8 years ago

@marcusnaslund

Yeah, to be honest I'm not too sure how useful auto generating this would be.
I see the appeal of just more information on the type but for most enums this is probably not a requirement.

Imho, it's pretty trivial to manually add a static function to do this, e.g.

Test: enum {
    A
    B
    C

    count: static func -> Int { 3 }
}

But of course, that is an extra bit of manual maintenance.

marcusnaslund commented 8 years ago

for most enums this is probably not a requirement.

That's absolutely true. It's just that I just had an enum which could really have benefited from an automatic count member.

Can we do it with a count() method so as to not overlap with any element? Or is that still going to be trouble?

marcusnaslund commented 8 years ago

@shamanas

Another idea related to enums: Make the elements cyclic. In other words, when you cast an Int to an enum type, to mod it by the number of enum elements.

I.e. with the above

x := 3 as Test
(x == Test A) toString println() // 3 % 3 = 0

would print true. Right now 3 as Test is perfectly valid, but nonsensical, and equals nothing.

This has the added benefit of giving the count of any enum as (-1 as myEnum) as Int + 1, though that's pretty hackish-looking.

alexnask commented 8 years ago

@marcusnaslund

Such a feature assumes that the enum starts at zero and that its members are consecutive integers, unless I am mistaken.
Both of those assumptions can be wrong, because of enum incrementers (I don't know if this is documented anywhere on ooc-lang.org anymore, but you can do stuff like Test: enum (*4) {, where the default is (+1) and you can use + and *), extern elements and setting specific elements to a value directly.

alexnask commented 8 years ago

Again, this functionality can be implemented through a from: static func (i: Int) -> This method or even an operator as (i: Int) -> TestEnum declaration, although this would be annoying to write for every enum.

ghost commented 8 years ago

I'd say casting a nonsensical integer value to an enum should throw exception or something. Hiding this with implicit modulo operation could cause some nasty bugs. I like the autogenerated count idea, though. As well as autogenerated array with all possible enum elements, sth like

Test: enum {
a, b, c
}
values : Test[] = Test values()
values[0] == a
values[1] == b
values[2] == c
marcusnaslund commented 8 years ago

assumes that the enum starts at zero

Oh yeah, nevermind.

thomasfanell commented 8 years ago

SomeEnum count() is ready for rock 1.0.22 if we still want this. If count() is defined manually, an error is raised: error 'count' is a reserved name for an auto-generated function.

At first I attempted to distinguish between static and instance functions, that is, we would allow non-static functions with the name count, but this does not seem to work, as the instance method is selected when we do SomeEnum count(). So for now, we have to disallow it completely.

Another option would be to set some suffix, but that might be hard to remember: SomeEnum count~generated()

thomasfanell commented 8 years ago

@sebastianbaginski I'll see if I can make that values to array thing happen. If we opt for that, then the count() function would be obsolete, since we could just check the array length property of the returned array. Oh well, we'll see.

thomasfanell commented 8 years ago
TestEnum: enum {
    ONE = 1,
    TWO,
    THREE
}
values := TestEnum values()
for (i in 0 .. TestEnum count()) {
    "%d" printfln(values[i])
}

// 1
// 2
// 3
marcusnaslund commented 8 years ago

Cool. :+1: It may not be the most requested feature, but I see no reason to throw it away.

ghost commented 8 years ago

Great :+1: Can you do toString() as well ?

TestEnum: enum {
    ONE = 1,
    TWO,
    THREE
}
values := TestEnum values()
for (i in 0 .. TestEnum count()) {
    values[i] toString() println()
}

// "ONE"
// "TWO"
// "THREE"

or maybe it already exists ?

thomasfanell commented 8 years ago

I was thinking of making something like toHashMap() -> HashMap<Name, Value>, but perhaps that is overkill...?

marcusnaslund commented 8 years ago

I think toString is enough. Also remember that the ooc-kean HashMap is not at all the same as the sdk HashMap, in case that causes any difficulties.

ghost commented 8 years ago

I don't know about hash, I just though that it could be nice with a built-in enum -> string, because when I need it in C I'm usually drowning in macros.

thomasfanell commented 8 years ago

I'll see what I can do

thomasfanell commented 8 years ago

Although I'm not too sure that values[i] toString() would work, since values[i] returns the item itself, an Int or an Float

thomasfanell commented 8 years ago

We'd have to create a wrapper for an EnumElement if we want this, I think...

ghost commented 8 years ago

OK, then maybe don't waste time on this if it's too complicated.

marcusnaslund commented 8 years ago

Yeah it's not important enough.

thomasfanell commented 8 years ago

Alright then, closing this..