Equivalent of classes in LiveCode

LiveCode is the premier environment for creating multi-platform solutions for all major operating systems - Windows, Mac OS X, Linux, the Web, Server environments and Mobile platforms. Brand new to LiveCode? Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

aetaylorBUSBnWt
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 118
Joined: Thu Sep 20, 2012 5:11 pm

Re: Equivalent of classes in LiveCode

Post by aetaylorBUSBnWt » Sat Aug 08, 2020 2:56 pm

FourthWorld wrote:
Sat Aug 08, 2020 2:37 am
Interesting design challenge, Mark. The rule as I stated it seems consistent, in that behavior1 well have access to behavior2, just as object1 has access to behavior1.

How might we declare that vars in a nested behavior break this rule and be available to something other than its immediate subscriber?

How do OOPs handle this? Do they treat a behavior1 class as though it doesn't exist, and everything up the chain is effectively flattened for the bottommost object using any of them!
OOPs have two kinds of fields & methods: public and private. Private can't be accessed from outside the class (unless the accessor is a friend class). While I don't remember attempting to directly accessing a private field of a superClass from a subClass, an instantiation of that subClass does have its own copy of that private field that would be used by those methods able to access that private field.

Public fields are accessible by anybody. Every subclass has access to all public fields in all its superClasses. When you instantiate a subclass, it has its own copy of all fields(private & public) found in all its superClasses. Subclasses don't have any specific knowledge of from which superclass a method or field comes from. If you wish to explicitly reference a particular superClass's version of a method, you would use className::methodName(....) to call that version of the method. To reference the first available superClass's method you would use super->methodName(....).

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: Equivalent of classes in LiveCode

Post by mwieder » Sat Aug 08, 2020 4:59 pm

Right.
LiveCode doesn't have a distinction between public and private class variables. They're all private except for (ick!) globals.
The way I'd expect to implement public variables in a class is to use getProp and setProp handlers or at least to resort to getters and setters.
Happily, I see that Brian's test stack is properly demonstrating just that with getters and setters, and if I modify it to use getProp/setProp handlers it also still works properly.

So there's something amiss in my code, and that narrows down my debugging task quite a bit. Thanks, Brian.
I'm in the process of converting Hakan's original OOP stack and Particles demo to use chained behaviors, and everything's working well except for this one little problem (always one more thing, no?)

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10045
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: Equivalent of classes in LiveCode

Post by FourthWorld » Sat Aug 08, 2020 5:33 pm

How valuable are getProp and setProp, since they are blocked by lockMessages?

I suppose if one never uses third-party code they can be useful, provided that one's own code is consistently diligent about never having messages locked while doing anything that might depend on them.

I've become a fan of getters and setters for this reason. Too bad; getProp and setProp were great contributions to xTalk, but rendered unusable in many scenarios by their dependency on having messages unlocked.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: Equivalent of classes in LiveCode

Post by mwieder » Sat Aug 08, 2020 6:04 pm

Hmmm... I'd forgotten about that.
The real advantage would be that we could have actual public variables in classes:

treat the class variables as if they were local variables

Code: Select all

# sVariable is a local variable in the behavior object
# using getProp/setProp handlers
set the sVariable of me to someValue
put the sVariable of me into someOtherVariable
instead of using getters and setters

Code: Select all

# using getters and setters
setSVariableTo someValue
put sVariable() into someOtherVariable
Public variables in a class are supposed to exist in the same scope as local variables in the object.

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: Equivalent of classes in LiveCode

Post by mwieder » Sun Aug 09, 2020 1:14 am

OK - I'm ready to toss this over for somebody else to figure out what I'm doing wrong.

Here's the update to Hakan's OOP stack and Particles demo stack.
I've reworked it to use chained behaviors (newObject -> gravityParticle -> particle).
And all works fine if I use normal particles.
When I switch to gravity or fuzzy particles it fails because the isAlive? function finds that _deathMoment is empty.
I've put several now-commented debugging statements in there, and it appears that the birth method is called, _deathMoment is properly initialized, but then it no longer has any content. Or at least content that can be retrieved.

So... anyone got a clue? I'm baffled.
Attachments
OOPMWLivecode.zip
(89.68 KiB) Downloaded 242 times

aetaylorBUSBnWt
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 118
Joined: Thu Sep 20, 2012 5:11 pm

Re: Equivalent of classes in LiveCode

Post by aetaylorBUSBnWt » Mon Aug 10, 2020 10:00 pm

FourthWorld wrote:
Sat Aug 08, 2020 5:33 pm
How valuable are getProp and setProp, since they are blocked by lockMessages?

I suppose if one never uses third-party code they can be useful, provided that one's own code is consistently diligent about never having messages locked while doing anything that might depend on them.

I've become a fan of getters and setters for this reason. Too bad; getProp and setProp were great contributions to xTalk, but rendered unusable in many scenarios by their dependency on having messages unlocked.
I am happy with the idea that I would have to have getters & setters for class variables - in the most rigorous C++ code you are supposed to be doing that anyway.

I spent some time going through Brian's code (THANKS for that) and believe I understand most of it. Wish the superclass could be designated by name instead of object ID, but at least the mechanism exists.

Questions:

It appears that a "function" in LiveCode ONLY returns a value. If you use it to set a value, that is really a side effect, correct?

So when people refer to getters and setters, they have to be implemented in the following way:

function getSomething
return sSomething
end function

on setSomething incomingValue
set sSomething to incomingValue
end setSomething

I just discovered in the documentation that LiveCode has redefined the meaning of "function" to "getter".
(RunRev is definitely pushing "assume" to its limits.)

Or is it really that setting anything is required to be through the "on" thing?

So getProp and setProp cause "lockMessages" to be set true?

What doesn't cause lockMessages to be set true?

Thanks,
Andrew

SparkOut
Posts: 2945
Joined: Sun Sep 23, 2007 4:58 pm

Re: Equivalent of classes in LiveCode

Post by SparkOut » Mon Aug 10, 2020 10:45 pm

aetaylorBUSBnWt wrote:
Mon Aug 10, 2020 10:00 pm
So getProp and setProp cause "lockMessages" to be set true?
No, not at all.
getProp and setProp will be blocked by having lockMessages set to true*, so the problem is that you have to rely on the coder not locking messages at any point where the get/setProp handlers are expected to work. If you are coding solo and know at all times that this isn't a factor, then you are ok. If coding in a team and not intimately aware of the lockMessages state then this could be a problem.

* you will see a note in the dictionary that lock messages can be required to prevent runaway recursion if setting a property referenced in the handler.

For the rest, it's a bigger discussion that I am not confident about articulating, especially not while typing on this phone keyboard.

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: Equivalent of classes in LiveCode

Post by mwieder » Mon Aug 10, 2020 11:13 pm

I just discovered in the documentation that LiveCode has redefined the meaning of "function" to "getter".
(RunRev is definitely pushing "assume" to its limits.)
OMG - where did you find this?
It appears that a "function" in LiveCode ONLY returns a value. If you use it to set a value, that is really a side effect, correct?
The comment about side effects is more or less true. I try to avoid side effects in my coding, but it's next to impossible *not* to have side effects in LiveCode scripting. And if you're careful about things it's not all that bad. I *do* try to keep my getters and setters as simple as possible.

Re: commands and functions, it's actually more complicated than that.
Commands as well as functions can return values, so the distinction gets a bit blurry.
The only real difference I can think of between command handlers and function handlers is in the calling syntax: a command is a verb at the beginning of a line and it doesn't use parentheses around its arguments; a function is the object of another command (most usually the keyword "put"). Also if you need the returned value of a command you need to get it explicitly in your code - the return value of a function is implicit.

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: Equivalent of classes in LiveCode

Post by mwieder » Mon Aug 10, 2020 11:21 pm

The original bug report on lockMessages was filed 17 years ago.
https://quality.livecode.com/show_bug.cgi?id=226

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10045
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: Equivalent of classes in LiveCode

Post by FourthWorld » Tue Aug 11, 2020 3:23 am

mwieder wrote:
Mon Aug 10, 2020 11:21 pm
The original bug report on lockMessages was filed 17 years ago.
https://quality.livecode.com/show_bug.cgi?id=226
Thanks, but after Mark Waddingham's reply when I brought this up on the list a few months ago, it seems unlikely to me that the proposed change will ever find its way into the engine.

I've been using getters and setters ever since lockMessages caused me a lost hour with getProp, so I just go on with those as though getProp and setProp don't exist, and I've been no worse for the wear.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: Equivalent of classes in LiveCode

Post by mwieder » Tue Aug 11, 2020 4:17 am

The problem isn't with lockMessages per se, it's more backwards compatibility... there's lots of code in the IDE, especially the datagrid, that uses lockMessages as a tool to prevent passing setting properties from causing unwanted side effects. Rewriting all that is a pain.

I've got a lockproperties property implemented here as a test... it's not that hard to do, and there are only two places in the code to insert it. But the IDE starts falling apart unless I implement it locally, and some of my own stacks do as well, since I've done the same sort of thing. I can't imagine this ever getting approved.

bwmilby
Posts: 462
Joined: Wed Jun 07, 2017 5:37 am
Contact:

Re: Equivalent of classes in LiveCode

Post by bwmilby » Tue Aug 11, 2020 5:43 pm

mwieder wrote:
Sun Aug 09, 2020 1:14 am
OK - I'm ready to toss this over for somebody else to figure out what I'm doing wrong.

Here's the update to Hakan's OOP stack and Particles demo stack.
I've reworked it to use chained behaviors (newObject -> gravityParticle -> particle).
And all works fine if I use normal particles.
When I switch to gravity or fuzzy particles it fails because the isAlive? function finds that _deathMoment is empty.
I've put several now-commented debugging statements in there, and it appears that the birth method is called, _deathMoment is properly initialized, but then it no longer has any content. Or at least content that can be retrieved.

So... anyone got a clue? I'm baffled.
It looks like trying to dispatch to a parent behavior isn't working as expected. When I traced the birth, it hit the birth on the gravityParticle button twice before going to the Particle button. My guess is that the script locals are all being set on the wrong instance. If I change the dispatch in birth and animate to a pass, then it seems to work properly. This should be fine if the parent doesn't need to execute first.

aetaylorBUSBnWt
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 118
Joined: Thu Sep 20, 2012 5:11 pm

Re: Equivalent of classes in LiveCode

Post by aetaylorBUSBnWt » Tue Aug 11, 2020 6:48 pm

bwmilby wrote:
Tue Aug 11, 2020 5:43 pm
mwieder wrote:
Sun Aug 09, 2020 1:14 am
OK - I'm ready to toss this over for somebody else to figure out what I'm doing wrong.

Here's the update to Hakan's OOP stack and Particles demo stack.
I've reworked it to use chained behaviors (newObject -> gravityParticle -> particle).
And all works fine if I use normal particles.
When I switch to gravity or fuzzy particles it fails because the isAlive? function finds that _deathMoment is empty.
I've put several now-commented debugging statements in there, and it appears that the birth method is called, _deathMoment is properly initialized, but then it no longer has any content. Or at least content that can be retrieved.

So... anyone got a clue? I'm baffled.
It looks like trying to dispatch to a parent behavior isn't working as expected. When I traced the birth, it hit the birth on the gravityParticle button twice before going to the Particle button. My guess is that the script locals are all being set on the wrong instance. If I change the dispatch in birth and animate to a pass, then it seems to work properly. This should be fine if the parent doesn't need to execute first.
I haven't looked at this code, but uppermost parent executing first is a key design feature of C++ classes.
For Constructors, the object created is the size and composition of the subclass itself, but then code execution starts from the top level parent and you work your way down to the lowest level class. This gives the subclasses the opportunity to change the original behavior without having to do all the work that is desired in the super classes where they are setting up their fields.
I suppose a workaround is that at each level of the birth method it could call its parent class birth method before doing anything else, then do its initialization work after the parent returns from its work.

The Destructor works the opposite way - subclasses clean up their stuff first and then each superclass is automatically called on the way up to the final superClass. Then the object's memory allocation is released after the final superClass destructor finishes.

The rest of the methods operate from the first level encountered on the way up the class hierarchy based on the object's class for a start point. Any such method can call its super class's method, but if it does not, then the superClass method is not executed.

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4171
Joined: Sun Jan 07, 2007 9:12 pm

Re: Equivalent of classes in LiveCode

Post by bn » Tue Aug 11, 2020 11:52 pm

bwmilby wrote:
Tue Aug 11, 2020 5:43 pm
It looks like trying to dispatch to a parent behavior isn't working as expected. When I traced the birth, it hit the birth on the gravityParticle button twice before going to the Particle button. My guess is that the script locals are all being set on the wrong instance. If I change the dispatch in birth and animate to a pass, then it seems to work properly. This should be fine if the parent doesn't need to execute first.
another way to get it working instead of passing is to change buttons "GraviytParticles" and "FuzzyParticles" to block "dispatch" in "birth" and "animate" and change "birth" and "animate" to "before" instead of "on" (apply those changes to both buttons, only "GravityParticles is shown here)

Code: Select all

before birth pX, pY, pdX, pdY, pLifeSpan, pParticleSource, pGravity
   --dispatch "birth" to the behavior of me with px, py, pdX, pdY, pLifeSpan, pParticleSource -- blocked BN
   if pGravity is empty then
      set the gravity of me to 1
   else
      set the gravity of me to pGravity
   end if
end birth

before animate
   set the dy of me to the dy of me + _gravity
   --dispatch "animate" to the behavior of me -- blocked BN
end animate
When a message is dispatched to a behavior of a control then "me" is the behavior and not the control. That is probably the root of the problem. The context is lost.

Kind regards
Bernd

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: Equivalent of classes in LiveCode

Post by mwieder » Wed Aug 12, 2020 12:19 am

Bernd- thanks. changing to before (and after in the case of "birth") handlers did neatly solve the problem while still maintaining the proper object inheritance path.

Brian- thanks also. Your clue about birth being fired twice gave me enough info to change "the behavior of me" to "the behavior of this me", and that helped get rid of the double invocation, but IsAlive?() still wasn't returning a non-empty value.

It's still a mystery to me why the dispatch to the IsAlive?() function wasn't doing the right thing, while removing the dispatch handler in the birth function does.

Andrew- yes, that's the way I have the constructors and destructors coded. The constructor starts at the highest level superclass and works its way down, the destructor starts at the lowest level class. Reference counting allows for cascaded destructors.

Here's the latest.
Attachments
OOPMWLivecode.zip
(89.64 KiB) Downloaded 215 times

Post Reply