Singleton : Fields vs Globals

BlitzMax Forums/BlitzMax Programming/Singleton : Fields vs Globals

tonyg(Posted 2008) [#1]
I have a singleton(-ish) type.
What is the difference between using fields and globals within the type?


Vilu(Posted 2008) [#2]
Well, you can access globals from other parts of the program without referencing to (or knowing about) any instance of the type. If you have a singleton type, you can always declare the type instance itself as global, so I guess it really makes no difference.

Performance-wise, I'm under the impression that only true program globals are significantly faster to use and access than local variables, and globals inside types aren't. So there's really no performance gain in using globals within type.


Perturbatio(Posted 2008) [#3]
Other than being able to access the global before the singleton is instantiated I don't know.

*EDIT*

I suppose a possible reason to use globals rather than fields could be that a module that uses the same singleton class can access them without knowing the name of the instance (but it's not really that useful).


tonyg(Posted 2008) [#4]
a module that uses the same singleton class can access them without knowing the name of the instance (but it's not really that useful).


That's why I was using globals to begin with rather than use a Get. I've switched back to using fields as that *feels* more correct.


Perturbatio(Posted 2008) [#5]
Just playing around, this seems to function just fine.

Type TSingleton
	Global singleton:TSingleton
	Field value:Int
	
	Function Create:TSingleton()
		If singleton = Null Then singleton = New TSingleton
		Return singleton
	End Function
End Type


Local a:TSingleton = TSingleton.Create()
a.value = 100
Local b:TSingleton = TSingleton.Create()
Print b.value



HrdNutz(Posted 2008) [#6]
You could access your singleton from anywhere without having an instance of the object if using globals and functions within the type, so I think it depends on the structure of your program, because having one instance of an object and accessing its fields would be similar to accessing globals of the type, except you don't need to have an instance for one.


Damien Sturdy(Posted 2008) [#7]
Wow pert, That's pretty nasty code lol. Doesn't do at all what the user would think if they didn't look at the Tsingleton class code directly. [edit: Actually Pert has a good idea, so I retract the preceeding statement!]

If you are creating a singleton twice, your code is wrong, so instead of "return singleton" I'd have something like a Runtimeerror stating you're using the class wrong.

Way I see it, once a class is completed, you shouldn't need to go back to that code. a Summary comment will (should...) show in the IDE as you're typing and this should be all you need to use the class.

Sadly, going off on a tangent, Blide is the only IDE I know of that makes use of Summary, and it only works in Windows. :-(

here's how I see it:

A global is persistent throughout all instances of a class, Which makes it useful to store something like a list of those instances in a Global.

TPlayer.GetPlayerlist() for example returns the Tplayers global List.

'Example Singleton. This is one of two ways, and you can use a Field just as I have used a Global,
'but you would need To keep a reference of what was created.
'The advantage of using the Global is that the code can simply be Tsingleton.GetInstance()
'instead of having a global instance elsewhere in the code, it is kept tidily in the Type interface.

Type Tsingleton
	Global Instance:Tsingleton

	'Summary: Constructor- Create the Tsingleton singleton.
	Function Create:Tsingleton()	'You could also overload the New function...
		If instance=Null Then
			instance=New Tsingleton
		Else
			RuntimeError "TSingleton is a Singleton. You may only create one instance!"
		EndIf
	End Function
	Function GetSingleton:Tsingleton()
		Return Instance
	End Function
End Type

'Example use of Global in a none Singleton:
Type Tplayer
	Global PlayerList:TList
	Field Name:String
	
	'Summary: Constructor- Create a player
	Function Create:Tplayer(name:String)	'You could also overload the New function...
		Local player:Tplayer=New Tplayer
		If Playerlist=Null Then playerlist=New TList
		playerlist.addlast(Player)
		player.name=name
		Return Player
	End Function

	'Summary: Retrieve a list of players.
	Function GetPlayerList:TList()
		Return Playerlist
	End Function

	'Destructor
	Method Delete()
		Playerlist.remove(Self)
	End Method
	
	
	'Summary: Get this current players name.
	Method Getname:String()
		Return Self.Name
	End Method
End Type


'Correct use of Singleton with this code:
'Create the Tsingleton instance.
Tsingleton.Create()	
'Call a second time? (should error and tell the coder he's cocked up!
'Tsingleton.Create()	

'Correct use of Tplayer:
Global Player1:Tplayer
Global Player2:Tplayer

Player1=Tplayer.Create("Damien")
Player2=Tplayer.Create("Tracy")

'Code that doesn't know what players have been created:
Local Playerlist:TList=Tplayer.GetPlayerList()
For Local Player:Tplayer=EachIn Playerlist
	Print "Look! I can see "+player.getname()+"!"
Next



ziggy(Posted 2008) [#8]
If it is a single instance type, there's no need to have any instance. yo can declare all as global and use functions. Even declare the type as abstract. That's the closest you'll get to create a shared object on BlitzMax


Ratchet(Posted 2008) [#9]
It's kind of offtopic but that's the way I learnd how to use a singleton:


Type TSingleton
  ...
End Type

Global FMySingleton: TSingleton

Function MySingleton: TSingleton
    If FMySingleton = Null Then
        FMySingleton = New TSingleton
    End If
    Return FMySingleton
End Function

'Somewhere in your code
MySingleton.SomeValue = 1
MySingleton.DoSomething()


You do not have to care about if your object was created or not. Also you always have just one instance and it will only created if you really need it.


Perturbatio(Posted 2008) [#10]
@Cygnus: That's my interpretation of how a singleton is supposed to function. i.e. a pattern that returns one instance and ensures you can't instantiate another. A runtime error would be a bad thing since what happens if you have a singleton used in two different modules within the same application?

Incidentally, your one requires that you already have the instance of the singleton when calling getSingleton since it's a method you're using not a function.

i.e. you'd have to do:
local a:TSingleton = TSingleton.Create();
Local b:TSingleton = a.getInstance();


Which is a tad pointless since you already have instance a.

The only difference between the code I wrote and the intention of your one appears to be that I used the create function to return the instance rather than encapsulating the return in a separate function.

Of course the create function could easily be renamed to getInstance and it would be exactly the same code but for some reason you'd have no problem with it.

The reason I use create is because all of my types use a create function.


Damien Sturdy(Posted 2008) [#11]
Oops! That SHOULD indeed be a function! ;-) Ta for spotting that!

Also, you're right regarding using a singleton with many modules, it's not something I've had to do, and it's a very valid point.

I also use Create. The above code (modified now to remove my bug!) is an example of the way we've built our Flow demo and it helps with fast development and also, if you decide to change the underlying engine, the interface doesn't have to change as long as you provide get/set methods. :-)

I DID have a rethink after Ratchet posted the code above and you are also right with Create/GetInstance(). They might as well all be the same code, it would make no difference. By the way ratchet, you should probably put your functions in the type!

In short, you've persuaded me that your way of using the Singleton is in fact valid and has more uses than my own code. :-)

Saying that, the Tplayer stuff in my code is also pretty handy for others ;-)


Perturbatio(Posted 2008) [#12]
In short, you've persuaded me that your way of using the Singleton is in fact valid and has more uses than my own code. :-)


Good, I was beginning to doubt myself for a moment there :)


Saying that, the Tplayer stuff in my code is also pretty handy for others ;-)



It does yes, that's actually very similar to the way I manage things like that (static list inside the type, etc.)


Damien Sturdy(Posted 2008) [#13]
I still prefer how I do it, I can just see how yours works.

I would have a problem with your code should the Singleton be for example the setup class of a 3D engine, where its parameters are set up at the start. If modules are used, and the instance doesn't exist, then there's a problem still, so it would be better to error out on Getinstance() when there is no instance, and to error out on a multiple create().

For example: If someone tried to make two instances of our Tgame class, it should error out because it doesn't make sense that it happened twice. You cant put the create() code in Getinstance() because it needs setting up with parameters.

Now, if you handle it by creating the instance and setting it up via other functions, fair enough. if all the create method is doing is creating a reference, then off you go, but somewhere, the parameters will need setting before some other code craps out without a meaningful message. :-)