[Home] [Downloads] [Search] [Help/forum]


Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ MUSHclient ➜ Development ➜ Current plugin scoping

Current plugin scoping

It is now over 60 days since the last post. This thread is closed.     Refresh page


Pages: 1 2  3  

Posted by Twisol   USA  (2,257 posts)  Bio
Date Mon 13 Sep 2010 05:51 AM (UTC)

Amended on Mon 13 Sep 2010 05:58 AM (UTC) by Twisol

Message
So I was mulling over a few different things, and I remembered how I was talking to you, Nick, about making the current-plugin management cleaner. My suggestion at the time had exception safety issues. But today I think I have a solution that's much cleaner -and- has no exception safety issues. Here's the code:

class PluginScoper
{
public:
  PluginScoper (CMUSHclientDoc* doc, CPlugin* plugin)
    : _doc(doc)
  {
    _saved_plugin = _doc.m_CurrentPlugin;
    _doc.m_CurrentPlugin = plugin;
  }

  ~PluginScoper ()
  {
    _doc.m_CurrentPlugin = _saved_plugin;
  }

private:
  CMUSHclientDoc* _doc;
  CPlugin* _saved_plugin;
};


Example:
{
  PluginScoper pscope (doc, plugin);
  // stuff here

  // automatically reset here
}


If an exception occurs anywhere within the scope, the destructor is automatically called as the stack is unwound. Also, it's destructed automatically at the end of its scope anyways.


I'm not planning on using this just yet, but it seems to be a nice construct, and I'll definitely be putting it on my list of cleanup ideas. What are your thoughts?

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #1 on Mon 13 Sep 2010 06:22 AM (UTC)
Message
Yes that looks very sensible.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #2 on Mon 13 Sep 2010 06:23 AM (UTC)
Message
Thanks!

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #3 on Mon 13 Sep 2010 06:25 AM (UTC)
Message
My only reservation is that plugins are usually called in sequence (ie. not just a single plugin). But with some modification the general idea could be retained, but go through all plugins.

In fact, what is done a lot is to:


  • Save the current plugin
  • Loop through all plugins
  • Ignore disabled plugins
  • To non-disabled plugins, take some action
  • Restore the saved plugin


All that could usefully be encapsulated.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #4 on Mon 13 Sep 2010 06:27 AM (UTC)
Message
Maybe your idea could just be in the inner loop, with the slight overhead of the constructor/destructor calls. But maybe there is a slightly better way.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #5 on Mon 13 Sep 2010 06:34 AM (UTC)

Amended on Mon 13 Sep 2010 06:35 AM (UTC) by Twisol

Message
If you want the quick and dirty way, just do this:

{
PluginScoper pscope (m_pDoc, NULL);

// a code loop
  {
  m_pDoc->m_CurrentPlugin = foo;
  }

// automatically reset here
}


I mean, I don't like it because you still directly affect the current plugin pointer, but it would work. I could add a new method to PluginScoper to let you indirectly affect the current plugin, but that would probably have un-obvious semantics when you have two of them in the same scope.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #6 on Mon 13 Sep 2010 06:34 AM (UTC)
Message
You know, Twisol, if you really want to get into this you should read up on "function objects" in STL. For example:

http://gammon.com.au/forum/?id=4181

You could iterate through a list (ie. all plugins) applying a supplied function object to them (ie. the action you want to take).

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #7 on Mon 13 Sep 2010 06:37 AM (UTC)
Message
Template:post=2896 Please see the forum thread: http://gammon.com.au/forum/?id=2896.


Template:post=2902 Please see the forum thread: http://gammon.com.au/forum/?id=2902.


et. al.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #8 on Mon 13 Sep 2010 06:38 AM (UTC)
Message
Yep, functors. I've used them before, though not extensively. I wrote a set of input/output stream manipulators you could use with cin/cout to change the text color and cursel location in the console.

I admit that I'm not sure what an elegant solution would be using functors; I haven't used them enough to have a real feel for where they fit best. I'll mull it over.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #9 on Mon 13 Sep 2010 07:22 AM (UTC)

Amended on Mon 13 Sep 2010 07:28 AM (UTC) by Twisol

Message
Okay, I have another idea. Instead of using PluginScoper to both store and set the current plugin, just use it to store the current plugin. Then you manipulate the current plugin pointer how you normally would. It's kind of like an auto_ptr.

class CurrentPluginScoper
{
public:
  CurrentPluginScoper (CMUSHclientDoc* doc)
    : _doc(doc), _saved_plugin(doc.m_CurrentPlugin)
  {}

  ~CurrentPluginScoper ()
  {
    _doc.m_CurrentPlugin = _saved_plugin;
  }

private:
  CMUSHclientDoc* _doc;
  CPlugin* _saved_plugin;
};


{
CurrentPluginScoper pscope (m_pDoc);

// a code loop
  {
  m_pDoc->m_CurrentPlugin = foo;
  }

// automatically reset here
}


The whole point here is to maintain the previous current plugin in an exception-safe way, and it has the desirable byproduct that it's cleaner, since you don't have to explicitly set it back. It still gives you full ownership of what the current plugin is, letting you do your plugin loops while maintaining previous context.

I just asked myself what the simplest thing that could possibly work would be, and this is what I got.

[EDIT] The name is dreadful; I'm open to suggestions.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #10 on Tue 14 Sep 2010 07:30 AM (UTC)

Amended on Tue 14 Sep 2010 07:35 AM (UTC) by Twisol

Message
By the way, I read that Lua uses setjmp and longjmp for error handling (and coroutines), so if you use lua_error() and it skips past one of these - or really, anything that has a destructor - it'll never be destructed. That's a very, very nice pitfall that seems really easy to fall for...

[EDIT]: *facepalm* Of course, the very next e-mail I read in the mailing list archives is by Nick.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #11 on Tue 14 Sep 2010 03:48 PM (UTC)
Message
Quote:
CurrentPluginScoper

CurrentPluginContext? Python calls this sort of thing a 'context', although it also has more explicit syntax support.

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #12 on Tue 14 Sep 2010 06:34 PM (UTC)
Message
I was thinking about that, but it's not really a context. Nothing changes unless you set the current plugin yourself, all this thing does is guarantee that it's set back.

CurrentPluginSaver?

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #13 on Tue 14 Sep 2010 06:40 PM (UTC)
Message
I would make it so that the scoped object takes care of setting and restoring, to be explicit. Is there a reason why you'd save it, set it later, and restore it upon destruction? Why not save+set on construction and restore on destruction?

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #14 on Tue 14 Sep 2010 06:59 PM (UTC)
Message
Because of the point Nick raised before, about how he loops over many plugins rather than just one. We could have a plugin scoper in the inner loop that's constructed/destructed every time, but frankly that's a bit disgusting. You could put the plugin scoper outside the loop and start it with NULL, but then you're circumventing the class.

I thought about it, and all we really need is a way to save and restore the current plugin. We can leave the actual current-plugin management to the user code. Of course, you can do this:
PluginScoper& operator= (CPlugin* plugin)
{
  _doc->m_CurrentPlugin = plugin;
  return *this;
}


Then you'd have something like this:
{
  PluginScoper current_plugin(m_pDoc);

  // some dummy loop here
  while (true)
    current_plugin = some_plugin;
}


Honestly, I just think the semantics could get confusing if you have multiple scopers in the same scope. But if that's something we can deal with easily, well okay then.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


85,272 views.

This is page 1, subject is 3 pages long: 1 2  3  [Next page]

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]