Why isn't Null a constant in Blitz?

Blitz3D Forums/Blitz3D Programming/Why isn't Null a constant in Blitz?

big10p(Posted 2005) [#1]
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.


Stevie G(Posted 2005) [#2]
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.


big10p(Posted 2005) [#3]
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. :/


Stevie G(Posted 2005) [#4]

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!!


gosse(Posted 2005) [#5]
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



Stevie G(Posted 2005) [#6]
Can't do that ... you get an illegal type conversion.


Floyd(Posted 2005) [#7]
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.


big10p(Posted 2005) [#8]
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.


Floyd(Posted 2005) [#9]
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.


Koriolis(Posted 2005) [#10]
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.


Barliesque(Posted 2005) [#11]
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.


nawi(Posted 2005) [#12]
This is an awful workaround, but seemed like good idea to post


Type 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



Koriolis(Posted 2005) [#13]
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.


Warren(Posted 2005) [#14]
Free Noel!


Rook Zimbabwe(Posted 2005) [#15]
I have always thought that foo was null... Was I wrong?


Barliesque(Posted 2005) [#16]
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


Koriolis(Posted 2005) [#17]
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...


Barliesque(Posted 2005) [#18]
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?


Koriolis(Posted 2005) [#19]
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=


Barliesque(Posted 2005) [#20]
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.


Nexic(Posted 2005) [#21]
Uhhh I thought Null just equals 0?


big10p(Posted 2005) [#22]
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.


Scherererer(Posted 2005) [#23]

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.