• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Struct extension constructor problem

Status
Not open for further replies.
Level 24
Joined
Aug 1, 2013
Messages
4,657
Lets say I have this script:
JASS:
struct A
  
    readonly boolean b
  
    public static method create takes nothing returns thistype
        local thistype this = .allocate()
      
        call .doSomething()
      
        return this
    endmethod
  
    private method doSomething takes nothing returns nothing
        call BJDebugMsg(".b = " + B2S(.b))
    endmethod
  
endstruct

struct B extends A
  
    public static method create takes nothing returns thistype
        local thistype this = .allocate()
      
        set .b = true
      
        return this
    endmethod
  
endstruct

Doing:
call A.create()
Will print ".b = false"
But doing:
call B.create()
Will also print ".b = false"

How can I run a method in the constructor of A that waits for the constructor of B to be finished?

I have a Unit struct and a Hero struct.
When a unit is created, I create another unit to show the health bar.
However, heroes have different versions of the health bars.

Hero extends Unit and the check of wether or not the instance is of type Hero, aka return .getType() == Hero.typeid doesnt detect the hero type until the hero constructor is finished.


EDIT:
For now, I will use factories, but if anyone has a better (more eye-candy) idea, then please share.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
For the most part you do not want parent class constructors to depend on subclass method implementations. This is because subclass methods should be able to assume that parent class state is initialized when they are called and parent class state initialization should be unaware that it is part of a subclass, if any. The reason this is a good idea to do is that it reduces cross class coupling and creates a strict and well defined state initialization model.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Since it doesn't look like anyone has clearly stated what's wrong, any time (in basically any OOP language) you construct an inherited class it runs the constructor for the parent before the child, and any time you destroy one it runs the destructor for the child before the parent.

There are a few viable ways to make part of A's constructor run after B's. Here are two:

Way #1: Threading (a 0-second timer will run after B's constructor).
Way #2: Make an "initialize" method in A and then do something like:

JASS:
struct A
    static method create ...
       ... //stuff that should run before B
    endmethod
    method initialize ...
       ... //stuff that should run after B
    endmethod
endstruct

struct B extends A
    static method create ...
        local B b = B.allocate()
        //do stuff
        b.initialize()
    endmethod
endstruct

However, in general what you are doing is very poor OOP design.
 
Last edited:
  • Like
Reactions: Rui
Level 24
Joined
Aug 1, 2013
Messages
4,657
However, in general what you are doing is very poor OOP design.
Then what should I do instead?
If it shouldnt be the constructor that depends on a subclass, what should I use then to create the health bars?

Also, I do use factories now:
JASS:
struct A
 
    public method init takes nothing returns nothing
     
    endmethod
 
    public static method create takes nothing returns thistype
        local thistype this = .allocate()
     
        return this
    endmethod
 
    public static method createA takes nothing returns thistype
        local thistype this = .allocate()
     
        call .init()
        return this
    endmethod
 
endstruct

struct B extends A
 
    public static method create takes nothing returns thistype
        local thistype this = .allocate()
     
        return this
    endmethod
 
    public static method createB takes nothing returns thistype
        local thistype this = .allocate()
     
        call .init()
        return this
    endmethod
 
endstruct

(final) struct C extends B
 
    public static method create takes nothing returns thistype
        local thistype this = .allocate()
     
        call .init()
        return this
    endmethod
 
endstruct
Aka, I do
A a = A.createA()
B b = B.createB()
C c = C.create()

(There is nothing that extends C.)
 
Last edited:
Level 24
Joined
Aug 1, 2013
Messages
4,657
If Hero overrides the method, that method wont be used.
Instead the one of the Unit would be used.

I could make it so the Unit constructor would create the bars and then the Hero constructor converts them to Hero bars, but they use different unit types to make the bars, so that isnt really optimal.
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
539
If Hero overrides the method, that method wont be used.
Instead the one of the Unit would be used.

I could make it so the Unit constructor would create the bars and then the Hero constructor converts them to Hero bars, but they use different unit types to make the bars, so that isnt really optimal.

You have to use stub-methods or interfaces.
 

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
539
stub methods dont work cause it would still think it is a unit
interfaces would kind of work, but then I have to split heroes from units which is not a good idea either.
mhhh i would need more context. i can't quite grasp what you're trying to do.
if i understood you correctly you'd just have to stub-overload the init method and then the call would correctly work on any extending struct.
 
Status
Not open for further replies.
Top