Super.Super not valid

BlitzMax Forums/BlitzMax Programming/Super.Super not valid

Grey Alien(Posted 2007) [#1]
bummer.

I wanted to call Super.Super.Manage() to call Manage from my based type, not the type in the middle. (I've extended twice from the base type).

Doesn't seem like you can typecast super either. I tried typecasting Super to the basetype and calling manage but that failed with a memory access violation e.g.

TDialog(Super).Manage()

This fails with the same error:

TDialog(Self).Manage()

I don't want to make a BaseClassManage() method or something lame.

Any other ideas?

thx.


AlexO(Posted 2007) [#2]
Type A

method MyMethod()
end method

end type

Type B extends A

end type

Type C extends B

end type


Local myType:C = C new.
A(C).MyMethod()

not tested as I'm not on my dev machine at the moment.
Blitzmax doesn't support overloading methods last I recall so why would calling the super method help? Or am I mis-understanding the issue (due to lack of context).


Gabriel(Posted 2007) [#3]
I have all my objects' hierarchy such that I only ever use Super in chains, like the new() and delete() methods. In other words :

eg:

Type firstleveltype
  Method Manage()
      ' FIRST LEVEL STUFF HERE
      '/FIRST LEVEL STUFF HERE
  End Method
End Type


Type secondleveltype
  Method Manage()
      Super.Manage()
      ' SECOND LEVEL STUFF HERE
      '/SECOND LEVEL STUFF HERE
  End Method
End Type


Type thirdleveltype
  Method Manage()
      Super.Manage()
      ' THIRD LEVEL STUFF HERE
      '/THIRD LEVEL STUFF HERE
  End Method
End Type


So it chains back up through the type derivations.


AlexO(Posted 2007) [#4]
Gabriel, I think that's what Grey was trying to avoid. He wanted to 'skip' the 2nd level if I understood correctly. Which to me sounds like a possible design issue.


Winni(Posted 2007) [#5]
Store a reference to the object in a static variable in a public function which returns the object in question. Using that function, you can call the method from anywhere without having to go through the class tree.


Gabriel(Posted 2007) [#6]
Gabriel, I think that's what Grey was trying to avoid. He wanted to 'skip' the 2nd level if I understood correctly.

I thought so too, but wasn't 100% sure. I posted the code example just to clarify. My main point was that I think objects should be planned such that skipping isn't required.

Which to me sounds like a possible design issue.

I agree. For me, inheritance says "Object B does everything that Object A does, plus some other stuff." If Object B doesn't do everything Object A does, it either shouldn't inherit from Object A, or another tier may be required inbetween, perhaps with abstract methods if it's just an implementation issue you want to skip, rather than a functional issue.


Grey Alien(Posted 2007) [#7]
Yeah I was trying to avoid the 2nd level stuff. It's probably bad design but like all these things, makes a lot of sense right now. So how to you say Object B inheritcs from Object A and Object C inherits from Object B but a few things in Object C are different rather than simply extended...

Winni. Yeah good point.

In the end I made a ManageCore() method and called that instead.


dmaz(Posted 2007) [#8]
why do you want to do that? if you really are thinking oop (no offense) you should never need super.super., you should always rely on what you extended from. which is ok since the second fully extends, has all methods and abilities of the first. it's easy to want to do this when you are doing all the coding for all the classes but you should try(always) to keep you extended type only knowing it's parent.

so you should either do
type first
	method manage()
	end method
end type

type second extends first
end type

type third extends second
	method manage()
		blah
		super.manage
	end method
end type

or add a manage method in the second...
method manage()
blah
super.manage
end method


Gabriel(Posted 2007) [#9]
So how to you say Object B inheritcs from Object A and Object C inherits from Object B but a few things in Object C are different rather than simply extended...

Well that's hard to answer without at least an abstract example of how it's different. Different implies it just implements things in a different manner in which case you either want Abstract methods in Object A ( if Object A is never instantiated ) or you want overridden methods in Objects B and C, but that doesn't really explain wanting to skip somethiing, so that's probably not what you mean by different. Does it do less? Does it do more? What makes it different?

If it at least does everything that ObjectA does, then you could have it extend ObjectA and move everything which B and C both do up the hierarchy into Object A, and then make those new methods abstract so that Objects B and C have to implement them. This. of course, assumes that Object A is an abstract object which you never instantiate - which may or may not be the case.


ziggy(Posted 2007) [#10]
I think Super is a compiler 'in scope' directive. It points to the underlaying extended type instance of an object and allows you to call its methods. As long a super is not a method, super.super is not allowed.


Grey Alien(Posted 2007) [#11]
Yeah basically Object A is TDialog and it's Abstract. Object B is a TDialogYesNo. Both have a Manage() method. B.Manage() calls Super.Manage() and that's fine.

So I wanted an Object C which was a variant of TDialogYesNo with different buttons and text layout BUT I can't alter Object B (TDialogYesNo) because it's part of my framework and other people need it. B.Manage() won't work properly for my new Object C, so I needed to call A.Manage() then some extra code for the new Object C.

Sometimes the problem with design is that once you've made something and released it to the public, you can't really go and change the way it works in a big way or you break their code. It's not the same as sitting down and designing everything from scratch OR being able to refactor your design later.

You *can* change the way it works internally though and that's why I added a ManageCore() method to Object A which A.Manage() calls. Then in C.Manage() I call ManangeCore and then my own code, which works fine because Object B doesn't override A.ManageCore() only A.Manage(). Make sense?


Gabriel(Posted 2007) [#12]
In the instance you've descibed, I'd create a new (abstract) type called TDialogBasicYesNo, and have the existing TDialogYesNo extend that. Then have TDialogAdvancedYesNo ( or whatever the new one will be called ) also extends TDialogBasicYesNo. Now you have some breathing room in what TDialogAdvancedYesNo and TDialogYesNo do because their manage methods are not related. Anything they still have in commmon can be shifted up to TDialogBasicYesNo and you haven't made any changes to TDialogYesNo, so your users can continue to use it as they are, completely unaware of any changes you've made.

It's an extra level of abstraction which I would normally try to avoid, but if you have to keep things unchanged for people who are already using the module, there has to be a price to pay somewhere.


Grey Alien(Posted 2007) [#13]
very good. I like it. It's 2am, surprise you can think straight ;-) I'm wired on Cola as I've just been to watch Die Hard 4.0.


dmaz(Posted 2007) [#14]
what Gabriel said....

or
you could do what we've seen before like in the win32 api and such...
create a new TDialogYesNoEx which extends from TDialog with all your new stuff.

or

sometimes when I have some function or method that I need to keep future proof but still compatible I use a TMap for the params or just a plain type that I can always add more fields to.


Dreamora(Posted 2007) [#15]
You could as well just do TDialog(self).blabla

instead of using some strange stuff, if you know to which base class you actually wanted to jump anyway :)


Grey Alien(Posted 2007) [#16]
That didn't work, I already tried it (and mentioned it in the first post).


Dreamora(Posted 2007) [#17]
hmm must have missed the part with self. that super does not work is clear, its no object.
But as self can be returned, I was under the assumption that it actually should work on self.


Grey Alien(Posted 2007) [#18]
Yep exactly what I thought but it gives and access violation. Self doesn't seem to be working quite the same as a normal object...


Dreamora(Posted 2007) [#19]
did you try to fake?
Just got an idea which perhaps works:

Method GetSelf:object()
return self
End Method


and then try to cast this one?
*if it works then self definitely needs to be fixed ... if it does not work, just return an input argument "obj:Object" which you return ... at latest at that point it will work*


QuietBloke(Posted 2007) [#20]
I would personnaly just go for Gabriel's solution rather than trying to do a fancy workaround which may work now but in the future might get 'fixed' which would break your code.
Its seems your Type C is not an actual extension of Type B. Its more like they are 'siblings' !?.
Therefore logically speaking you should have a type BC which extends Type A containing all the common code. Then Type B and C are extensions of Type BC with unique implementations of the Manage() method.

Of course its easy to say this from where Im sitting... I dont have a deadline to hit.

Good luck


Grey Alien(Posted 2007) [#21]
Dreamora: haha no I never tried that.

QuietBloke: Yeah BC would make sense. Like I said I got round it with a ManageCore() method. Bit of a cheat but its fine.


Azathoth(Posted 2007) [#22]
If casting to call the base method worked that would defeat the purpose of the vtable. The vtable is there so the correct method gets called on the current instance.


Picklesworth(Posted 2007) [#23]
You can't be completely assured what the type you are derived from is derived from. You can only be certain about that one Super, because Super's Super could in theory be changed to something else.
Okay, dumb thought...