Type global initilizers must be constant

BlitzMax Forums/BlitzMax Programming/Type global initilizers must be constant

Koriolis(Posted 2005) [#1]
Not really a bug report but rather a defect report, so to speak.
I don't understand why global variables inside types are restricted to constant values.
Global MyVar:MyType = New MyType compiles perfectly when outside of a type, but not within. Which can easily look inconsistent given that practically, putting a global variable inside a type affects only its scope.

This was for the "at first sight" side of things. Actually I do see the difference: when doing "Global MyVar:MyType = New MyType" at global scope we not only declare a variable, but also put a statement (MyVar = New MyType) in the main program code, *at the location of the declaration*.

When declaring a global variable inside a type, comes the question of where to put that "MyVar = New MyType" statement.

I'd like to advocate in putting it right before the type declaration.
That is
Type MyType
    Global obj:MyType2
End Type
is equivalent to
Global obj:MyType2
Type MyType
End Type
Except of course for the fact that you'd still access it via MyType.obj and not just obj

As long as it is clearly specified in the docs I can't see any problem with this solution.

A practical example of what it would allow:
Type MyType
    Global g_List:TList = New TList
    Method New()
        g_List.AddLast(Self)
    End Method
    Method Delete()
        g_List.Remove(Self)
    End Method
End Type
That is, emulating the blitzbasic global list for a given class. Currently we are forced to put the global variable at the global scope, and to pollute the global namespace with something that should really be inside the the type. Or worse, always check inside the MyType instances if the list is allocated and if not do it.


Robert(Posted 2005) [#2]
I suppose the problem is that outside of the type, it is very clear when the initializer code will be executed. But when should globals inside the type be initalized?


Dreamora(Posted 2005) [#3]
Type MyType
    Global g_List:TList = New TList
    Method New()
        if g_list = null
           g_list = new TList
        endif
        g_List.AddLast(Self)
    End Method
    Method Delete()
        g_List.Remove(Self)
    End Method
End Type



Koriolis(Posted 2005) [#4]
Sorry to quote myself guys ...

@Robert: That's exactly what I said. Or tried to say:
When declaring a global variable inside a type, comes the question of where to put that "MyVar = New MyType" statement.
and to me the solution seems simple:
I'd like to advocate in putting it right before the type declaration.


@Dreamora: This isn't a pleasing solution as I said:
Or worse, always check inside the MyType instances if the list is allocated and if not do it.

Simply because it adds an overhead. Sure this is mostly peanuts, but why having to live with it if the problem can be fixed easily by allowing non constant initializers? Also it simply makes the code less elegant and more error prone as you'll need to check g_List against Null every time you access it. In this case you'd better wrap that in a getter, which actually is a common idiom in other languages to enforce the singleton pattern
Type MyType
    Global g_List:TList
    Function GetGlobalList:TList()
        If g_list = Null
           g_list = New TList
        EndIf
        Return g_List
    End Function
    Method New()
        GetGlobalList().AddLast(Self)
    End Method
    Method Delete()
        GetGlobalList().Remove(Self)
    End Method
End Type

But that's another additional overhead. And I'd like to have the choice not to have this overhead. I think this is perfectly legitimate, especially when considering there is apparently no real problem in fixing this. If there is I'd simply like to know what it is.


Koriolis(Posted 2005) [#5]
Actually I think I will stick to the global inside types solution, and just put myself the "g_List = New TList" statement right before the type declaration (like I'd like BlitzMax to do for me behind the scenes).
MyType.g_List = New TList
Type MyType
    Global g_List:TList
    Method New()
        g_List.AddLast(Self)
    End Method
    Method Delete()
        g_List.Remove(Self)
    End Method
End Type
Which is already infinitely better than checking inside the MyType instances if the list is null or not.
And *certainly* not that bad considering that we can't hide g_List from the outside anyway, due to the lack of support for Private/Public inside types (might be another feature request..), so we'll always be able to initialize type globals from the main program. I must say I had missed this fact, how accostumed to hiding class members I am (in other languages).

But please Mark, take a moment anyway to consider adding this one day. Put that in your bag of minor but nice improvments.
Or drop a post if there is is some killer problem for doing it.


marksibly(Posted 2005) [#6]
Hi,

I'd like to see this in too, and it shouldn't be too tricky to add. Initializers would probably have to run *before* all main code, though, as you have to guarantee they execute.

Anyways, this is high on my list of non-module things to do!


Koriolis(Posted 2005) [#7]
Sweet. Glad to hear that :)
And indeed this is certainly better for the general case to make it execute before everything else in the current module/program (in the order of type globals declaration).
Thanks.