Best way to have "global" methods?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

Best way to have "global" methods?

Jeff M.
Okay, I'm still feeling quite new to Smalltalk, so I'm looking for
advice here (and hopefully not "omg, never use globals!"). :-)

When dealing with functionality that is "global", it would be nice if
all code could access it with as little work as possible. The exact
context I'm dealing with this in is OpenGL. Right now, I have an
OpenGLLibrary, which is a singleton instance, of course, and a
OpenGLView class has a class variable 'gl'. This gets initialized
something like this:

OpenGLView>>initialize
  gl ifNil: [ gl := OpenGLLibrary open ].
  "other init stuff here"

Now all my views can call OpenGL code just fine, it works, I'm happy.
The problem is that there will be [potentially] lots of classes that
need to call OpenGL functions. Consider a Vector class that wants to
call glVertex3f, or a Matrix class that wants to call glMultMatrixf.
Even being a singleton, I'd consider it a real pain if every instance
of all these classes has to point to the singleton instance of
OpenGLLibrary in order to call a function.

Now, I could always just not have an instance in all these classes, but
instead use OpenGLLibrary>>current to access the singleton (I suppose).
But this is going to result in unnecessary message passing in
performance critical code.

Is it possible to just make a "gl" global variable that all my other
objects can use? By the same token, is there a more common (and better)
solution to this problem?

Jeff M.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Ian Bartholomew-21
Jeff,

> Okay, I'm still feeling quite new to Smalltalk, so I'm looking for
> advice here (and hopefully not "omg, never use globals!"). :-)

Well....

> Now, I could always just not have an instance in all these classes, but
> instead use OpenGLLibrary>>current to access the singleton (I suppose).
> But this is going to result in unnecessary message passing in
> performance critical code.

Message passing is very efficient and the small number of extra message
sends involved, when compared to the total number of message sends, should
be insignificant (but see below).  All the Dolphin base image libraries use
the singleton #default method and, to be honest, I wouldn't really consider
doing it any other way.

Just make your OpenGLLibrary a subclass of ExternalLibrary and use
OpenGLLibrary>>default to access the library instance.   If performance is
*really* that critical then you can override the class side #default method
(see PermanentLibrary and ScintillaLibrary for a couple of examples) but you
will then have to make sure the Library is opened and closed yourself.



FWIW, you _can_ use globals in Smalltalk. Evaluate

Smalltalk at: #GL put: WinMMLibrary default

to create a global object named GL that contains an open instance of
WinMMLibrary.  You can then send it messages from anywhere ....

GL timeGetTime

but,  "omg, never use globals!"    ;=)

--
Ian

Use the Reply-To address to contact me (limited validity).
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Jeff M.
In reply to this post by Jeff M.
Thanks for the reply. I mixed up Current and #default, thanks for the
correction. :-)

I appeciate the options mentioned. I'll have to do some timings, but if
the message passing is as fast as you suggest, then perhaps this isn't
as big a deal as I think it is. I'd just like to get it right the first
time before having to go back through a lot of code....

As for the "omg, never use globals!", I just didn't want an academic
response to the question. There is nothing inherently wrong with
globals: it's just another tool available, and if it is part of the
best solution, use 'em. ;-)

Thanks again! I'll take a closer look at PermanentLibrary and see if
there is anything there that might help me.

Jeff M.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Martin Rubi
> I appeciate the options mentioned. I'll have to do some timings, but if
> the message passing is as fast as you suggest, then perhaps this isn't
> as big a deal as I think it is. I'd just like to get it right the first
> time before having to go back through a lot of code....

Just in case you don't know the tool already, you can use Ian's great
profiler to find out where the time goes.

best regards
martin


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Ian Bartholomew-21
In reply to this post by Jeff M.
Jeff,

>  I'll have to do some timings, but if
> the message passing is as fast as you suggest, then perhaps this isn't
> as big a deal as I think it is. ....


I think you'll find that the compiler knows about methods that just return
an instVar and optimizes them so that they don't need a full method
evaluation.  The interpreter can just answer the contents of the instVar
without having to evaluate any code.  That's why the debugger doesn't step
into simple accessor methods - there's no code to step through.

--
Ian

Use the Reply-To address to contact me (limited validity).
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Jeff M.
In reply to this post by Martin Rubi
Does someone have a link to this tool?

Jeff M.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Jeff M.
In reply to this post by Jeff M.
Past experience has taught me to never just "trust the compiler". :-)

However, if I find through equal experience that Dolphin does a fine
job of optimizations, there's another great reason for me to purchase
sooner rather than later.

Jeff M.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Ian Bartholomew-21
In reply to this post by Jeff M.
Jeff,

> Does someone have a link to this tool?


It's on of the goodies available from my web site.

http://www.idb.me.uk

Like the rest of the goodies it's getting a bit long in the tooth now and
could do with a rewrite.   I should say that it's not particularly good for
timing low level operations[1], for that I would still use the tried and
trusted Time>>millisecondsToRun .

[1] Dolphin only generates interrupts at certain times (entry and exit from
a method send) so the profiler, which uses the VM interrupts to take
samples, struggles when a method doesn't contain any/many message sends.

--
Ian

Use the Reply-To address to contact me (limited validity).
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Blair McGlashan-4
In reply to this post by Jeff M.
"Jeff M." <[hidden email]> wrote in message
news:[hidden email]...

> Okay, I'm still feeling quite new to Smalltalk, so I'm looking for
> advice here (and hopefully not "omg, never use globals!"). :-)
>
> When dealing with functionality that is "global", it would be nice if
> all code could access it with as little work as possible. The exact
> context I'm dealing with this in is OpenGL. Right now, I have an
> OpenGLLibrary, which is a singleton instance, of course, and a
> OpenGLView class has a class variable 'gl'. This gets initialized
> something like this:
>
> OpenGLView>>initialize
>  gl ifNil: [ gl := OpenGLLibrary open ].
>  "other init stuff here"
>
> Now all my views can call OpenGL code just fine, it works, I'm happy.
> The problem is that there will be [potentially] lots of classes that
> need to call OpenGL functions. Consider a Vector class that wants to
> call glVertex3f, or a Matrix class that wants to call glMultMatrixf.
> Even being a singleton, I'd consider it a real pain if every instance
> of all these classes has to point to the singleton instance of
> OpenGLLibrary in order to call a function.
>
> Now, I could always just not have an instance in all these classes, but
> instead use OpenGLLibrary>>current to access the singleton (I suppose).
> But this is going to result in unnecessary message passing in
> performance critical code.
>

The normal thing to do would be to use 'OpenGLLibrary default' rather than
hold onto the instance. The level of indirection is useful in allowing the
library to be re-opened on demand on image restart. In D6 you can hold an
instance, since the default instance is always re-used (so you won't end up
referencing a stale instance on restart), but at some point you need to
cause that instance to be re-initialised. Sending #default to the library
class will do that.

If it is really performance critical you can make OpenGLLibrary be a
subclass of PermanentLibrary. This means that it is explicitly opened on
image start, rather than lazily. This cuts the cost of accessing the default
instance substantially, since a method activation is not needed. You can
time the relative performance by comparing:

1) Time microsecondsToRun: [10000 timesRepeat: [AdvApiLibrary default]]
2)  Time microsecondsToRun: [10000 timesRepeat: [KernelLibrary default]]

I think you will find that the latter runs about 5x faster than the former,
and in fact if one eliminates the loop overhead the permanent library access
is about 7.5x faster. YMMV.

> Is it possible to just make a "gl" global variable that all my other
> objects can use? By the same token, is there a more common (and better)
> solution to this problem?

Yes, although I don't think you will need to. The overhead of a "partial"
message send to get the default instance of a permanent library will
probably be insignificant in relation to the cost of most external calls.
Bear in mind that the whole Dolphin base image is built using 'XXXLibrary
default'.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Chris Uppal-3
In reply to this post by Jeff M.
Jeff,

> Okay, I'm still feeling quite new to Smalltalk, so I'm looking for
> advice here (and hopefully not "omg, never use globals!"). :-)

Unlikely to get that advice -- Smalltalk makes /very heavy/ use of globals,
whenever you use a class name you are refering to a global variable ;-)


> Is it possible to just make a "gl" global variable that all my other
> objects can use? By the same token, is there a more common (and better)
> solution to this problem?

You've already been given the right answers to this.  I just wanted to add a
note that if you did want to use this kind of achitecture, you should ensure
that your system hooks the #onStartup event triggered off SessionManager
current, and uses that to clear or reset the value of the global.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Jeff M.
In reply to this post by Blair McGlashan-4
> If it is really performance critical you can make OpenGLLibrary
> be a subclass of PermanentLibrary. This means that it is
> explicitly opened on image start, rather than lazily.

Can I ask how the image does this? Is it just a hard-coded feature of
Dolphin somewhere internally (ie, for i = 1 to num_subclasses do load)?
Or is this some feature I can leverage elsewhere in my code (I'm
assuming through the #onStartup that others have mentioned)?

Thanks again. I must say, as usenet groups go, this is one of the best
I've come across. :-)

Jeff M.


Reply | Threaded
Open this post in threaded view
|

Re: Best way to have "global" methods?

Ian Bartholomew-21
Jeff,

> Can I ask how the image does this? Is it just a hard-coded feature of
> Dolphin somewhere internally (ie, for i = 1 to num_subclasses do load)?
> Or is this some feature I can leverage elsewhere in my code (I'm
> assuming through the #onStartup that others have mentioned)?

ExternalLibrary is a bit of a special case as it needs to be started very
early on in the startup process.  Because of this it is hard coded into the
startup sequence.

Most other code, both in the base image and in any additions that have been
installed, will use Dolphin's event mechanism to receive a notification that
the image has been started.  The SessionManager triggers a number of events
(#sessionStarted, #sessionStopped etc) at appropriate times and these can be
used to instigate appropriate actions.

As an example look at the Chat class.  When you open a Chat window the
#createSchematicWiring method tells the SessionManager that, in future, it
wants to be informed when the session starts and names a method, #onStartup,
that should be called.  If you exit and save the image with the Chat window
open then the next time you start Dolphin the #onStartup method will be
invoked to ensure a stable startup state.


Note that there are other ways you can achieve initialization when the image
is restarted, overriding various methods in the SessionManager hierarchy for
example.

--
Ian

Use the Reply-To address to contact me (limited validity).
Mail sent to the From address is ignored.