Alternative to singleton

Started by
64 comments, last by ApochPiQ 12 years ago

If two scopes have completely different lifetimes, they cannot share their contents without duplication/[font=courier new,courier,monospace]memcpy[/font]ing. Ref-counting is not used for most assets.
You can however form a parent/children hierarchy of scopes that can share assets up the tree. E.g. if a "level-chunk" scope was parented under a "whole-level" scope, then if you asked the "level-chunk" scope to load an asset that already existed in it's parent, then the asset would not be reloaded (it would be fetched from the parent).


The situation I've dealt with in the past is the user 'equipping' a skill or weapon in an RPG, and having the need to pre-emptively load all assets that might subsequently be used for that selection. Assets are potentially shared between related scopes in this scenario, and in a heavily memory bound system like the last generation of consoles, duplicating asset data is something to be avoided. The sharing needs to happen horizontally (between siblings), not vertically between a parent/child. I can't see a safe way to achieve this type of differential loading (load scope B, but reference any shared data from sibling scope A) without some kind of reference counting mechanism. This is not to say reference counting couldn't be implemented relatively easily into the asset scope framework you have described. This may not be suitable if the memory fragmentation associated with such an approach is a problem. It was the right fit for one specific project I worked on, with load times down to a fraction of what they would otherwise be, by allowing preloading of almost all level assets during character/level select screens.


What processing operations / data transformations does the entity node provide? In this case, if it's only required to group sub-objects in the editor, then it doesn't need to exist in the game -- the car will emerge simply by loading the actual components that were specified under the car node, without creating a representation of the car node itself.

It provides no data transformations, existing only as a point of reference, a collection of properties (expressed as interfaces at the entity level) defining a logical entity. It will have a tree of objects below it (chassis, wheels, whatever), but the actual control interfaces - how it translates user inputs, or whether an AI operates it, will be (optionally) defined by interfaces assigned to that root 'car' node.. or it won't have any interfaces associated with it, in which case it will basically exist as a static object.


Just because your XML is a "scene graph" of nodes, that doesn't mean that your de-serialised XML data has to follow the same structure. You could dump all the car-components into the scene and connect them to each other without having an node retaining links to them.

Yes, though the car could be considered a component in and of itself, having intrinsic properties (or, it might not..). If not, you might choose instead to express a car as a collection of networked (linked) entities as you describe - though some designers might find this a bit cumbersome (if they want to link another entity to the 'car', can they still link it to the root car node given it has no direct runtime representation?).


Passing the map of factories into the entity only makes sense if the Entity's purpose for existing is "parsing XML files". In that case, then before parsing an XML file, I'd construct a map containing all of the factories that your scene XML files could possibly require, and use that map during any deserialisation routine. However, in this case, I'd move this logic out of the Entity class altogether and into an XmlSceneParser instead... and again get rid of the Entity as a misplaced concept, or find it's real purpose and make it do that.


I agree the loading is better done from some loading/parsing framework, completely outside of entity. Except where you start drilling down to concrete implementations, for example loading an EngineDynamicModel component or something - where data to load is a bit more private in nature.
Advertisement
*sigh* Potatoman... I give up.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

Look at "AssetManager". What does it do? It... uh... manages assets... but... how? What does it really actually do? Does it load assets? Does it store them in a cache? Does it free them when they're no longer in use? Does it just load raw bytes, or does it construct objects from the loaded raw bytes? If it constructs objects, what kind of objects? There are lots of different kinds of assets. What if I want to load compressed data; can it decompress? If so, what compression formats does it support? None of these questions, and many others, are clear when using these amorphous manager classes.


A thought occurred to me earlier, pretty much all of the functionality you describe above (and then some) is embedded within the windows API CreateFile/ReadFile. First let me say the windows API is not an example of good design, and that is not where I'm going with this. What I do wonder, however, is whether you mutter curses each time you have to use these API functions? Are they really all that bad, do they prevent you from getting your job done? Would you be more productive, your applications more stable/efficient/readable, if there was a different implementation provided? There are plenty of windows framework calls that genuinely do make life difficult, I just think the file IO routines are pretty low on this list.

When I asked the same question on a thread earlier - how would people replace the OS filesystem (a global), nobody cared to respond. How would you go about structuring a filesystem, to access media content, while supporting concurrency, caching, decompression, decryption, prioritization, networking (among other things). Would you take all these individual components and 'pipe them all together' before going to load a file, or perhaps manage the coordination of all these subsystems in a central place, providing a common interface?

On a side note - would it be fair to say you're just as opposed to any class with 'system' in the name, such as 'FileSystem' (in the same way you avoid manager)?

When I asked the same question on a thread earlier - how would people replace the OS filesystem (a global), nobody cared to respond.

It isn't really a global, at least not for some time now.

Any modern OS allows multiple concurrent file read/writes to take place - even from different threads. If you wrap it all up in a monolithic 'FileSystem', then you have just serialised one of the few subsystems that was implicitly parallel.

On a side note - would it be fair to say you're just as opposed to any class with 'system' in the name, such as 'FileSystem' (in the same way you avoid manager)?[/quote]
That's a bit of an edge case, since you are representing an existing concept known as a 'file system'. Naming rules are relaxed when representing real-world concepts.

However, if you handed me an 'AISystem', or a 'RenderingSystem', I would look at you funny.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

@Potatoman: I don't know why I'm responding, but I am. Your questions about the file system thing are exactly why I'm not using PhysicsFS. It seems nice and all, but I can't use its global state. The global state makes it useless to me. The whole point of PhysicsFS is to have a virtual file system, but what's the point of having a virtual file system if you can only have one virtual file system? I know why PhysicsFS says it's nice to use their virtual file system, but really, the global state ruins all the potential of having virtual file systems. If you aren't sure why I say this about PhysicsFS, try and think of why.

And about the CreateFile/ReadFile stuff... what the heck are you talking about? CreateFile/ReadFile don't serialize bytes into objects; they don't handle compression/decompression; etc.

And swiftcoder's response about the "System" thing is the same as mine.

And now I really am done with this thread.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

It isn't really a global, at least not for some time now.

Any modern OS allows multiple concurrent file read/writes to take place - even from different threads. If you wrap it all up in a monolithic 'FileSystem', then you have just serialised one of the few subsystems that was implicitly parallel.


I'm curious to hear if other people share this view. Surely globals/singletons are not acceptable on the basis of whether they gracefully handle concurrent operations? Indeed new/delete come under this banner, and this has already been flagged as an undesireable on this thread.


And about the CreateFile/ReadFile stuff... what the heck are you talking about? CreateFile/ReadFile don't serialize bytes into objects; they don't handle compression/decompression; etc.

You can compress system volumes, you can encrypt them. Readfile doesn't return encrypted/compressed data, so where do you think this is being handled? I'd say about the same place it would happen on a ResourceServer (or whatever you would call it, I've never seen so much concern over a class name before). They don't serialize bytes into objects, which is why I said 'pretty much all' in my last post. Performing deserialization into objects is one of the more trivial components of a resource loader.

If you cannot see how file IO API calls represent a global state, I don't really know what to say.
I think we've had about enough of this thread.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

This topic is closed to new replies.

Advertisement