Why isn't Null a constant in Blitz?
Blitz3D Forums/Blitz3D Programming/Why isn't Null a constant in Blitz?
| ||
As the title says. I need to be able to pass an optional type handle to a function, like:Function do_stuff(x, y, parent.myType=Null) I just get an error message basically saying that Null isn't a constant. This little gem has really screwed up my plans. :/ Anyone know why Null isn't a constant in blitz, then? Beats me. |
| ||
Completely agree .... I ran into this recently with a routine where I wanted to average between 2 and 4 vector types ... Avg ( 2 [no of vectors], v1.vector , v2.vector , v3.vector, v4.vector ) If I only wanted to average the 1st two vectors , the only way I could get round it was to create a dummy vector type and pass that as both V3 and V4... even though I had no use for them. I just stuck to haveing a different function for each ... quite annoying. I'd be interested if anyone has a better solution. |
| ||
The only other way I could think of was to have a Global type handle which I set before calling the function - like having a global function param. Yuck! Unfortunately, I don't really have the option of duplicating the function for different amounts of params because it contains a large Select/Case for initializing types to presets. Duplicating this and remembering to keep them in sync would be a real pain. I just can't think of a reason why Null isn't a constant. :/ |
| ||
The only other way I could think of was to have a Global type handle which I set before calling the function - like having a global function param. Yuck! That's what I meant ... total pish!! |
| ||
Well, you can always have a Global instance to compare with. example: type mytype ... end type global nullmytype.mytype function dostuff(param1.mytype, param2.mytype = nullmytype) if param2 = nullmytype then ... you have it when its null end function |
| ||
Can't do that ... you get an illegal type conversion. |
| ||
Null really is not constant. When you Delete a Type object it isn't actually deleted. It is moved to an 'inactive objects' list. Any variable referring to such an object is considered Null, even though the value of that variable is not zero. A call to New will recycle an inactive object, if one is available, rather than allocate new memory. This speeds up the New/Delete system, but has the annoying side effect that Null is not a valid default value. It's usually not too hard to work around this. The Avg ( 2 [no of vectors], v1.vector , v2.vector , v3.vector, v4.vector ) is one example. You can't have a variable number of type arguments, so the [number of vectors] argument is needed. You must then supply four vectors no matter how many you really wanted. Example: Avg ( 2 , v1, v2 , v1, v1 ) to average the first two vectors. The final v1,v1 will be ignored. |
| ||
So, when I have a line like:If this.myType = Null Then ... It's not only checking to see if this.myType equals 0, but also checking to see if this.myType matches a handle of any of the deleted types held in the 'inactive objects' list? Ahhh, that would explain why Null isn't a constant, then. Thanks for the explanation, Floyd. ;) However, this raises a few other concerns: - If I have many (thousands) of deleted types, wouldn't the If check above take a relatively long time, since it would have to go through the handles of all the deleted types? - If memory used by deleted types is never actually freed (until the program ends), it's possible to have memory bloated with thousands of deleted types, pushing the memory requirements of an app up unnecessarily. |
| ||
1. I assume this is implemented in such a way that Biltz knows which list an object is in without actually searching the list. So checking =Null should not slow down as the number of deleted objects increases. 2. It is true that memory used by Type objects goes up but never down. It is always a kind of 'high water mark'. I suppose you could cook up an example of this which causes problems. But in practice I doubt you will see any bad effects. |
| ||
This speeds up the New/Delete system, but has the annoying side effect that Null is not a valid default value. This is all but a reason for having Null not being seen as a constant. When you do "If MyObject = Null" the compiler knows perfectly well you're not comparing apple to bananas, but an object reference to a another object reference.Internally these references are nothing but straight pointers. If Null simply maps to the pointers whose address is 0, comparing a reference r1 to another reference r2 could simply be done like that (pseudo C code, p1 and p2 being the corresponding pointers): result = (isDead(p1) ? 0 : p1) == (isDead(p2) ? 0 : p2) That is, before doing the comparison, simply force the pointers to 0 if they point to a dead object (every dead object could have a simple flag set). By doing this, the blitz compiler could simply map Null to the pointer of address 0 (that is, a constant, so no problem). Given that this is certainly what Blitz already does internally, there is AFICT really no good reason to have Null not being seen as constant. It's just done like that. |
| ||
I don't think that whether Null is a constant or not is really the issue--It's certainly not a variable. Regardless of what Null is, big10p's function declaration ought to compile. If a variable of MyType can be initialized to Null, then it stands to reason that Null should be a valid default value. I say, post it in the bug reports forum. |
| ||
This is an awful workaround, but seemed like good idea to postType Foo Field Bar End Type TestFoo() fish.Foo = New Foo TestFoo(Foo(fish)) Function TestFoo(t=0) f.Foo = Object.Foo(t) If f.Foo = Null Then Print "Foo is null!" Else Print "Foo is not null!" End Function WaitKey Function Foo(f.Foo) Return Handle(f.Foo) End Function |
| ||
I don't think that whether Null is a constant or not is really the issue--It's certainly not a variable By definition if it's not a variable it's a constant and vice versa. So yes it's the issue. If a variable of MyType can be initialized to Null, then it stands to reason that Null should be a valid default value Certainly. I say, post it in the bug reports forum. Problem is, this is all but a new issue. It was already reported several times, and if it wasn't fixed before BlitzMax, chances are slim that it will be from now. Sadly. |
| ||
Free Noel! |
| ||
I have always thought that foo was null... Was I wrong? |
| ||
By definition if it's not a variable it's a constant and vice versa. So yes it's the issue. It seems to be behaving as neither constant nor variable (despite the syntax), but as a keyword of the compiler. Which means it's up to the compiler to interpret that keyword appropriately. I'm suggesting that it would be appropriate for the compiler to interpret NULL in a useful way as a function parameter default. Problem is, this is all but a new issue. It was already reported several times, and if it wasn't fixed before BlitzMax, chances are slim that it will be from now. Sadly. Well, I'd have thought it to be the other way round. They're a small team and can't really be expected to divide their attention evenly across several products all the time. Once BlitzMAX is released for PC and initial bug reports are cleared, I would imagine they'll be better able to divert attention back to Blitz3D. Anyway... This is an awful workaround, but seemed like good idea to post Well, I don't think it's a bad work-around at all--especially it's brought to light a function I had no idea even existed: Handle() ...How long has that little beauty been around?! I just updated my help system with the latest, and that's still not in there! ...Aaaargh! :-S |
| ||
Which means it's up to the compiler to interpret that keyword appropriately Excatly my point of view. How long has that little beauty been around Very long. Search in the forums you'll find pleanty of threads.Byt I agree with nawi, the sample is pretty awful. Being able to have Null as a default parameter is just a neat convenience, and this workaround is all but nice to use, which defeats the purpose IMHO. Oh and when I say it's been requested several times, I am not lying. I had requested it myself: http://www.blitzbasic.com/archive/posts.php?topic=19612 It was 2 years ago, so guess what are the chances of getting it implemented... |
| ||
Actually, I take that back. It's great that it works and it's possible to do, but it's hardly the kind of elegant program construction that I've generally found possible with Blitz3D. Is there anywhere in particular that hidden functions like Handle() have been collected and documented? |
| ||
There's a bit of information on undocumented features onblitzcoder http://www.blitzcoder.com/cgi-bin/code/code_listentries.pl?id=UD I wouldn't say it's complete, but ta least it does exist. Then for more information on specific features, google is your friend. By example you can find quite a lot of thread about handle/object: http://www.google.com/search?hl=fr&q=site%3Ablitzbasic.com+handle+object&btnG=Recherche+Google&meta= |
| ||
Thanks for the tip. The BlitzCoder site has a lot of useful information. Seems to me it would still be worthwhile collecting together information about ALL of the undocumented features, in one place. |
| ||
Uhhh I thought Null just equals 0? |
| ||
Nope. Read Floyd's first post to see why. In the end, I got around the problem by making the type params mandatory, and then just passing in Null when I don't need them. |
| ||
Well, you can always have a Global instance to compare with. example: type mytype ... end type global nullmytype.mytype function dostuff(param1.mytype, param2.mytype = nullmytype) if param2 = nullmytype then ... you have it when its null end function Remedied with Handle()... It should work. |