Using Self as a Method Default
BlitzMax Forums/BlitzMax Programming/Using Self as a Method Default
| ||
Here's what I'm trying to do. I want to use self as a method default like so.Method Sample(a:blah, b:blah = self) self.ni = b.n + a.n End Method I get a "Self can only be inside a Method" error. Is there any way to make a default the main type being used? |
| ||
No. And why would you need to? its allready itself ;) Id rather use Null and test for that instead. |
| ||
Method Sample(a:blah, b:blah = Null) If b=Null Then b=Self self.ni = b.n + a.n End Method ? |
| ||
Also, on a similar note, the Defalt has to be a constat anyway doesnt it? So even if you could use self outside the main body, it would fail, cos self isnt Constant. You need to use code like Gabs if you want to set a global as default. |
| ||
Gabriel and grable: I'm already using null and an IF statement in that manner. There's a slight hit in performance and while it's not that big of a hit, I think being able to put self as a default would speed it up and be worth it. If I can find someway to be able to make a default the self then I can eliminate the IF statement. EDIT: H&K: I've already been doing what Gabriel posted since the beginning. And yes, according to the docs a default has to be a constant. But since it has to be a constant I guess this is a dead issue unless there's some undocumented magic way to do it. |
| ||
There's a slight hit in performance errrrr... how slight?<edit> and how do you know? |
| ||
I'm already using null and an IF statement in that manner. There's a slight hit in performance and while it's not that big of a hit Well...... call me stupid if you want, but.. for you to have thought that self would work, then you must be calling the method from/by some other method/object of that type, so why dont you just pass self as a parrameter? But to be honest I wouldnt worry about the hit, less you are calling it millions of times. And in that case I would write two different ones. |
| ||
But to be honest I wouldnt worry about the hit, less you are calling it millions of times. And in that case I would write two different ones. And in that case the function call overhead is way more than a single If ;) |
| ||
Can you say param=MyGlobal (a global variable) and set a Global to the Self of that object e.g. MyGlobal=MyType, so that if you don't pass something to the method it uses the global which happens to be the self of that object? |
| ||
@Angel, I dont think you can. My experiance has been that the Param has to be a constant And in that case the function call overhead is way more than a single If ;) Yep, but then we should all use gotos all the time ;)My point being that if you had two different methods, one where you were passing a param, and one where you werent, which you selected at write time, then it would be faster than a function call and an if. |
| ||
Here's a method. Not sure if it is any faster, thoughMethod Sample(a:blah, b:blah = null) self.ni = (self.n * Not(b)) + b.n + a.n End Method |
| ||
True H&K, but it's all apples and oranges. You can have 2 separate methods or you can have an if statement and take a small hit that you wouldn't notice anyways. Here's the full experiment. As most of you know I've written/translated a math/vector lib over the years. They've been used a lot by quite a few people and have shown up in many demos. There is one thing I want to point out to Josh though but I'll get to that in a bit. I'm taking each math method and stuffing it inside a bare bones loop. While Not KeyHit(KEY_ESCAPE) Cls For a = 1 to 1000000 v1.Add( v1, v2 ) Next 'FPS Show_FPS() Flip 0 Wend I do this with each method and do the internal works a few different ways, keeping the fastest iteration. If I do a straight: Method Add(a:TVector3) self.x :+ a.x self.y :+ a.y self.z :+ a.z End Method I get an FPS of 57 (very slow machine btw). And then I use this as a baseline. Now, if I do a: Method Add(a:TVector3, b:TVector3 = Null) If b = Null Then b = Self self.x = b.x + a.x self.y = b.y + a.y self.z = b.z + a.z End Method This way gets 55 fps but allows me to write it either v1.add( v2 ) or v1.add( v2, v3 ). There's a little more versatility there. And I ponder, is the tiny bit more versatility worth 2 fps when cycling it 1 million times? Might seem very trivial to you guys, but I'm writing my final math lib here. It's in the archives and growing almost every day. So now you know what exactly I was trying to do. If I could set the 2nd argument in the method to self, then I could avoid the 2 fps hit and have the versatility also. ie. Have my cake and eat it too. To Josh/Halo/Leadwerks: The original BMax math lib I put into the archives is SLOW. Creating a new vector type for each method was a bad call on my part and there's a significant hit with it. Bad way: Method Add:Vector( v:Vector ) Local res:Vector = New Vector res.x = self.x + v.x res.y = self.y + v.y res.z = self.z + v.z Return res End Method Best way: Method Add(v1:Vector, v2:Vector) self.x = v1.x + v2.x self.y = v1.x + v2.y self.z = v1.x + v2.z End Method or Method Add(a:TVector3) self.x :+ a.x self.y :+ a.y self.z :+ a.z End Method Doing it the way above yields about a 400% increase in speed. The bad way above also showed up in a TQuaternion part of MiniB3D if I'm not mistaken. Changing it to the Best Way should speed things up immensely. |
| ||
Bad way:Method Add(v:Vector) Local res:Vector = New Vector res.x :+ v.x res.y :+ v.y rex.z :+ v.z Return res End MethodYou do realise that youare not actuly adding anyhting here dont you? And you cannot return anything Method Add(V:Vector) Self.x:+ V.x Self.y:+ V.y Self.Z:+ V.z Endmethod PS. Im not saying do it like this, just that thats how I do it. I have SM_Add and RM_Add (Because I do have two differnt ones, depending on if I am adding a vector to self, or adding the vector and self and passing the result to somthing else |
| ||
H&K: That was a typo and it's fixed now. In your 2nd method there's no reason to have return self in your method. I guess if you're passing it on to something else you could just use the method on the vector you want to pass it to. passto.add( v1, v2) or v1.add( v2 ). If you had an IF statement you could use 1 function and write it either way. |
| ||
If you want to avoid `if's`, sometimes a function pointer is a good way as it takes you directly to the code that you want. |
| ||
Hmm...if there was someway to point to the self from the method line without and special pre calc set up. It's beyond me. |
| ||
If your 2nd method there's no reason to have return self in your method. I guess if you're passing it on to something else you could just use the method on the vector you want to pass it to hahahWe actualy had quite a long thread about this. And the conclution was 1) The speed difference was very small. 2)It was faster to return self but not allocate it, than not to return anything. If you had an IF statement you could use 1 function and write it either way. Well yes ;) that has been the point of my posts.My general rule is, if its not in the game loop make the methods as general as possible, if it is in the game loop make them as specific as possible. And yes, V1.SM_add(V2) V3=V1.Rm_add(v2) |
| ||
If you want to avoid `if's`, sometimes a function pointer is a good way as it takes you directly to the code that you want. AFAIK you can only use ptr with an int? I tried using a Ptr to my type but I get Illegal Pointer Type error. |
| ||
you can only use ptr with an int For example Field F_BeatFunction(Me:TBeat,event:TEvent) Is a field pointer to a function that takes a beat and an event as paramaters |
| ||
H&K: Can you use a pointer as a method default to point to the invoked type? |
| ||
Here's something that's weird. The fastest method gets 57 fps (in a 1 million cycle loop with Flip 0). If I do it this way (notice the 'this' field): Type TVector3 Field x:Double, y:Double, z:Double Field this:TVector3 Function Create:TVector3(x:Double = 0, y:Double = 0, z:Double = 0) Local v:TVector3 = New TVector3 v.this = v v.x = x v.y = y v.z = z Return v End Function Method Add(a:TVector3, b:TVector3 = Null) If b = Null Then b = self.this self.x = b.x + a.x self.y = b.y + a.y self.z = b.z + a.z End Method End Type I get 56 fps which isn't a bad hit at all and lets me write it both ways of v1.add( v2 ) and v1.add( v2, v3). For some reason, setting b to a field that's holding the type is faster than just setting b to self. /shrug |
| ||
Gabriel and grable: I'm already using null and an IF statement in that manner. There's a slight hit in performance and while it's not that big of a hit, I think being able to put self as a default would speed it up and be worth it. Not that big of a hit? I tried running the function with and without an if 5 milliion times and they're both showing identical times ( to the nearest millisecond, which is all I can be bothered to code ) so I'm struggling to see the hit myself. |
| ||
so I'm struggling to see the hit myself In my eyes, that's a good thing. :) |
| ||
Self might require indirectly accessing such as myinstances.mytype rather than if a field contains the self it would just be mytype. ?? I'm not sure I still understand why you want to pass self to a method, when methods can only ever refer to one self. Is it just so you can pass some other self to it from a different instance? Why would that instance not be using its own methods? |
| ||
Originally I wanted to do this:Method Add(a:TVector3, b:TVector3 = Self) self.x = b.x + a.x self.y = b.y + a.y self.z = b.z + a.z End Method So I could eliminate an IF statement. B would default to self if no vector was passed to it. But I can't do it and the IF statement is a neglibible speed hit anyhow. |
| ||
If you are curious about speed, try this, the method I posted above. I have to admit that I'm curious if it's any faster than an if myself ...reposting: Method Sample(a:blah, b:blah = null) self.ni = (self.n * Not(b)) + b.n + a.n End Method If b isn't passed in, the expression evaluates to self.ni = self.n * 1 + 0 + a.n if b is passed in it evaluates to self.ni = self.n * 0 + b.n + a.n |
| ||
Testing now...brb. EDIT: Ouch! That cut the speed by 50%. Very innovative attack to the problem though. |
| ||
Again, if you are worried about speed, just have two different methods that you select at write time. It seems stupid to me to spend all this effort when as you type in the code you know if you are passing a parameter or not. And if you are not then select the method that takes one parameter and uses self. If so, then use the method that takes two parameters. (And if you are really worried that some times the paramater that you pass might be NULL and you want to use the first method, then right a third one that choses between the two, which you only call in that very rare situation) New basic rule, if you are worried about the speed of an If and IFing at write time is possible, then IF at write time. You are a lot better off with slightly larger code. |
| ||
It seems stupid to me to spend all this effort It's really no effort. And my original question was answered. You can't put a self as a method default. At this point we're just having fun. /shrug |
| ||
New basic rule, if you are worried about the speed of an If and IFing at write time is possible, then IF at write time. You are a lot better off with slightly larger code. This is where something like Lisps macro's would be nice. Basically, the macro would be evaluated at compile-time and could expand into either of the two separate calls based on if the parameter or present or not. I.E, you get the speed of "IF'ing at write time", while you get the coherence of a single type of function call. |