ENIGMA Forums

Contributing to ENIGMA => Proposals => Topic started by: RetroX on January 06, 2011, 07:50:50 pm

Title: Object member functons
Post by: RetroX on January 06, 2011, 07:50:50 pm
It would be really cool if, somehow, ENIGMA would be able to do something like:
Code: [Select]
obj.instance_destroy();instead of:
Code: [Select]
with(obj)
{
  instance_destroy();
}

Basically, calling a function as a member function would merely mean applying it as a with() statement with only one line.  And there might be optimisations for it, too, for example:
Code: [Select]
obj.f1();
obj.f2();
would be parsed to:
Code: [Select]
with (obj)
{
  f1();
  f2();
}

Granted, you could abuse this and do things like obj.draw_set_color(), but it's still a nicer syntax (and you can do that in with(), too).  Obviously, with() would have to be used for ifs and loops, but for simple functions, writing it out this way just looks nicer.

I dunno how doable that this would be, but I think that it would be a really nice thing to have.
Title: Re: Object member functons
Post by: freezway on January 06, 2011, 08:07:31 pm
AGREED!
Title: Re: Object member functons
Post by: IsmAvatar on January 06, 2011, 09:53:06 pm
I'm with you.
Title: Re: Object member functons
Post by: Fede-lasse on January 07, 2011, 02:52:03 am
Looks like some sort of "exceptional rule", but then again, there's a lot of those in GML.

Would save time nonetheless.
Title: Re: Object member functons
Post by: polygone on January 07, 2011, 07:44:26 am
Given this suggestion, how would this be interpreted?

Code: (EDL) [Select]
a = obj.f1();
Title: Re: Object member functons
Post by: luiscubal on January 07, 2011, 12:04:39 pm
@polygone

Code: (EDL) [Select]
//a declared outside the with
with (obj)
   a = obj.f1();
Title: Re: Object member functons
Post by: polygone on January 07, 2011, 12:33:57 pm
What?

Anyway never-mind it would clearly have to syntax error. This couldn't be used for anything other than straight executing functions.
Title: Re: Object member functons
Post by: RetroX on January 07, 2011, 04:05:33 pm
Given this suggestion, how would this be interpreted?

Code: (EDL) [Select]
a = obj.f1();
Code: [Select]
global var ______ENIGMATEMP;
with (obj)
{
  ______ENIGMATEMP = f1();
}
a = ______ENIGMATEMP;

By "parse," I didn't mean textually.  I meant to replicate its usage.

All that with() does is change enigma::instance_event_iter to the current object.  a = obj.f1() simply would mean change the event iter, however, operate on a local variable.
Title: Re: Object member functons
Post by: polygone on January 07, 2011, 04:45:39 pm
Using with seems counter-intuitive to me given how gml works. Because when an object_index is given in gml in variable assignment it only assigns to the first instance of the object, unlike with which assigns to all the instances.

Code: [Select]
obj.a = value;  //assigns to just the first instance of obj

with (obj)
{
  a = value;  //assign to all instances of obj
}
Thus if the dot syntax was used for executing functions it seems better to me if it does not use with, but rather only executes to the first instance of obj in order to keep the notation consistent.
Title: Re: Object member functons
Post by: RetroX on January 07, 2011, 05:03:13 pm
Yeah, that would make sense.  Still think that it would be a good idea to have an option for all objects, though.
Title: Re: Object member functons
Post by: polygone on January 07, 2011, 05:08:36 pm
Yeah, that would make sense.  Still think that it would be a good idea to have an option for all objects, though.
Given that you would want to change the object_index.variable = value interpretation to every instance at the same time. Otherwise this code would be counter-intuitive:

Code: (EDL) [Select]
obj.a = obj.f1();As it would only assign a to the first instance of obj whereas it would loop f1() with all instances of obj. It is not possible though to change them to loop through all instances of objects because it will be too much work for the interpreter to do.

Which is why I originally suggested it should just syntax error, but given that only the first instance of obj is used than I believe it is doable, it would just be like replacing obj.f1() to the return value of f1() executed in the scope of the first instance of obj.
Title: Re: Object member functons
Post by: RetroX on January 07, 2011, 05:21:05 pm
That's why I'm saying that it should be made as an option. :V

Use member functions like regular variables.  Then, add a configuration option to make both variables and functions operate on all objects.
Title: Re: Object member functons
Post by: polygone on January 07, 2011, 05:44:56 pm
Then, add a configuration option to make both variables and functions operate on all objects.
It's not reasonable to let them to be changed to loop through all instances otherwise you can start doing all sorts of crazy shit. Like this:

Code: (EDL) [Select]
obj1.a = obj2.array[obj1.f1(), obj2.f2()];
Title: Re: Object member functons
Post by: IsmAvatar on January 07, 2011, 06:04:27 pm
You're going to have to explain that one to me... because I don't see what's wrong with it.
Title: Re: Object member functons
Post by: polygone on January 07, 2011, 06:12:54 pm
How would that be interpreted?
Title: Re: Object member functons
Post by: IsmAvatar on January 07, 2011, 07:00:49 pm
Suppose f1 and f2 return 0, and obj2.array[0,0] = 0.

The statement would be equivalent to the following:
obj1.a = 0;

As you can see, I'm totally lost, which is why someone needs to explain this one to me.
Title: Re: Object member functons
Post by: RetroX on January 07, 2011, 08:54:16 pm
It would be expansion hell.

Now, that makes sense, I guess.

with() will do what it will, I suppose.
Title: Re: Object member functons
Post by: RetroX on January 07, 2011, 08:55:20 pm
Suppose f1 and f2 return 0, and obj2.array[0,0] = 0.

The statement would be equivalent to the following:
obj1.a = 0;

As you can see, I'm totally lost, which is why someone needs to explain this one to me.
f1() is performed for all objects, f2() is performed for objects, and set to a for all objects.  It would be expansion hell, and really, in the end, the last one executed would actually be stored.  That's why it's a bad idea to make one variable operate on multiple objects.
Title: Re: Object member functons
Post by: polygone on January 08, 2011, 07:02:47 am
Suppose f1 and f2 return 0, and obj2.array[0,0] = 0.

The statement would be equivalent to the following:
obj1.a = 0;

As you can see, I'm totally lost, which is why someone needs to explain this one to me.
As RetroX has just said, because what if there are multiple instances of obj1 and obj2? You can't run things so straight then. f1 and f2 might return different values depending on the instance it was executed with.

RetroX has stated as a solution:
Quote
in the end, the last one executed would actually be stored
But to me this is really not nice and I don't think it is a viable solution. Which is why I mentioned previously:

Code: (EDL) [Select]
obj.a = obj.f1();People would naturally expect this to work like:

Code: (EDL) [Select]
with (obj)
{
  a = f1();
}
But it would instead work like:

Code: (EDL) [Select]
global var ______ENIGMATEMP;
with (obj)
{
  ______ENIGMATEMP = f1();
}
with (obj)
{
  a = ______ENIGMATEMP;
}
Title: Re: Object member functons
Post by: r9k on January 08, 2011, 08:57:17 am
Suppose f1 and f2 return 0, and obj2.array[0,0] = 0.

The statement would be equivalent to the following:
obj1.a = 0;

As you can see, I'm totally lost, which is why someone needs to explain this one to me.
As RetroX has just said, because what if there are multiple instances of obj1 and obj2? You can't run things so straight then. f1 and f2 might return different values depending on the instance it was executed with.

RetroX has stated as a solution:
Quote
in the end, the last one executed would actually be stored
But to me this is really not nice and I don't think it is a viable solution. Which is why I mentioned previously:

Code: (EDL) [Select]
obj.a = obj.f1();People would naturally expect this to work like:

Code: (EDL) [Select]
with (obj)
{
  a = f1();
}
But it would instead work like:

Code: (EDL) [Select]
global var ______ENIGMATEMP;
with (obj)
{
  ______ENIGMATEMP = f1();
}
with (obj)
{
  a = ______ENIGMATEMP;
}

There are no ______ENIGMATEMP. The parser will just convert "obj." to enigma_varaccess and everything will be as fast as a c++ member function call and assignation.
Title: Re: Object member functons
Post by: Josh @ Dreamland on January 08, 2011, 11:22:38 am
Unfortunately, r9k, it's not that simple. It's not as simple as polygone's suggestion, either.
The only way to implement this cleanly is too flawed to implement:
Code: (GML) [Select]
obj1.func()
becomes
Code: (C++) [Select]
(enigma::with_iter(obj1), func())
When the expression starts, it will be as though it was executed for obj1. When the expression ends, the with_iter will destruct, and the code will be back in its original scope. However, this will fail catastrophically:
Code: (GML) [Select]
obj1.func(obj2.func())
Both will be executed for obj2. This is because at the beginning of the expression, obj1 is pushed as the current instance, then obj2 is as well.

I haven't yet found a way around this.
Title: Re: Object member functons
Post by: RetroX on January 08, 2011, 12:51:20 pm
Polygone, I wasn't suggesting any solution.  I was mentioning what would actually happen.

I think that, like obj.x, obj.func() should only operate on one instance.
Title: Re: Object member functons
Post by: luiscubal on January 08, 2011, 01:36:01 pm
Perhaps you should have with_iter use some sort of stack?

(enigma::push_with(obj1), func(enigma::push_with(obj2), func(), enigma::pop_with()), enigma::pop_with());
Title: Re: Object member functons
Post by: RetroX on January 08, 2011, 05:33:38 pm
That was actually what he mentioned doing, I believe.
Title: Re: Object member functons
Post by: Josh @ Dreamland on January 09, 2011, 12:41:29 am
That's how with_iter works, luis. Issue is, you just passed func() the return value of enigma::pop_with().
Title: Re: Object member functons
Post by: luiscubal on January 09, 2011, 08:09:54 am
I see.
What about:
Code: [Select]
(enigma::push_with(obj1), enigma::pop_with((enigma::push_with(obj2), enigma::pop_with(func()))))where pop_with(K) returns K.

If with_iter is already a stack, then I don't see how "obj1.func(obj2.func())" would fail. After all:
Code: [Select]
(enigma::with_iter(obj1), func((enigma::with_iter(obj2), func())))The inner func is called after obj2 is pushed to the stack, and before it is poped, so it is applied to obj2 alone, the top() of the stack(assuming a STL stack)
The outer func is called after obj1 and obj2 are pushed to the stack, but obj2 was already poped, so obj1 is the top() of the stack and therefore func() is applied to obj1 alone.

So I think it would work. That is, unless C++ sequence points are playing tricks on me.
Title: Re: Object member functons
Post by: Josh @ Dreamland on January 09, 2011, 01:12:24 pm
The stack is pushed twice at the beginning of the expression in my example, then popped twice right after.

pop_with(K) was what I was considering. But it wasn't until you posted it again that I realized I was thinking about it incorrectly. My first instinct was that there'd be no way to instantiate a template because the return type of func() can't be gathered from &func. But now I see that a simple template function would have done it.

Code: (C++) [Select]
inline template<typename any> any& pop_with(any &r) { return r; }

So thank you, Luis; the simplicity of the matter escaped me.