Some precautions on using modules

● ARCHIVED · READ-ONLY
Started by Engr. Adiktuzmiko 15 posts View original ↗
  1. Modules (or their properties/attributes/variables etc) seem to be not capable of recognizing things below it when setting up constants (at least that's where I encounter problems).

    This is important for some things like XS Menu for example which uses a module for setting up it's menu list (directly declaring a Scene name inside the module). Because of this behavior, all custom scenes that you will call via XS menu must be above it else it will return an error because it will try to find the scene inside the module. It's actually because of this script that I remembered that modules seem to work that way.

    Code:
    #this returns an error when the custom scene script was below xailmodule somemoduleMENU_BLAH = [BLAH,Scene_Custom_Scene]end#But it now works when the Custom Scene script was placed above XAIL
    I'm not sure of any other script out there that is afflicted with that problem but I think it's for the benefit of everyone to remember this behavior of modules.
  2. That has nothing to do with modules, but sequential code execution.

    X is not defined when it is referred to in line 3 (Height = ...). The interpreter has no idea what to do with it. It could be a string, an array, anything.  Put those three lines in any script and you'll get the same error.

    Edit: Ruby being as extremely OO as it is, what X is, is an Object (or BaseObject now in Ruby 1.9). The arithmetic operators aren't defined for the BaseObject or Object class.

    Incidentally, sequential code execution is one of the three fundamental control flow structures required to solve algorithms (loops and conditional branches being the other two).
  3. I just said modules since that's where I encountered it... and also because it was actually mainly about XAIL's script


    where this didn't work


    module somemodule


    SOME_VARIABLE = MY_CUSTOM_SCENE


    end


    when the custom scene script was below XAIL


    But yeah I was thinking probably it's because it was initializing constants so positioning is important...


    PS: Anyone who knows a lot more is free to clarify things up. :)
  4. Ok, I see what you're getting at now - the example you gave used variables but I think what you're really talking about are forward function (method) calls. I'd have to look it up to see how Ruby deals with those at runtime. In C, you put the headers ahead of where they need to be and you can define the functions later on (necessary if two functions call each other). Ruby doesn't have those, so it's got to have some way of checking - or the circular function thing wouldn't work, which I know it does.

    Part of the advantage of an interpreted language is the ability to do things like that.

    It's also part of the disadvantage of an interpreted language, as well...
  5. I do think the problem is with the fact that it was still on initializing phase during the constant setting part so it can only look for things that are already initialized... so it might indeed be because of the sequence. :)


    So I think it's just that it's more likely to happen in modules used for settings. Especially on the case presented where we directly set a Class into a constant variable inside a module. Because otherwise (like the original example) it is pretty obvious that it won't work.


    PS: I was actually amazed when RGSS3 was able to do calls to functions/methods below the call coz I'm used to wc3 where it's also not allowed.
  6. I dont know if its ideal, but you could just predefine all used classes before the module:

    class Scene_Test < Scene_Base; end; module Test  abc = Scene_TestendThen the position of the Script which contains the class doesnt matter anymore.

    One of the problems is, that you need to know the superclass
     
  7. That's what I do for some of my code. I just forward declare all classes that other constants depend on at the top of the file, then write the definitions that use them and the classes themselves in the order that logically makes sense later in the file.
  8. Your original question has already been answered (kind of, the answer is actually quite simple), so I'd just like to say this: the XS Menu using constants is totally unnecessary. Symbols could be used just as easily, and a constant can be generated from them using Object.const_get(symbol). Likewise, you could use anything that can be converted cleanly into a symbol and just cast the object to a symbol in the call to const_get.

    Honestly, using constants to build a menu list is just silly. And if the developer was concerned about nested constants (like Module::Scene), that's easily taken care of:

    Code:
    class String  def to_const    split('::').reduce(Object) { |obj, const| obj.const_get(const) }  endendmodule Example  CONSTANT = :valueend'Example::CONSTANT'.to_const # => :value
  9. From what I understand (and I'm probably wrong, since Modules still confuse me), Modules act like singleton classes -- whereas a class won't throw an error until you try to instance it, Modules are essentially instances of the Module class itself. So when you're defining a Module, it's actually running the variables, etc. that you put outside of any method definitions as it sees it. Whereas classes don't do that, because class initialization doesn't happen 'til you instance the class.

    So essentially, from what I can recall,

    I do think the problem is with the fact that it was still on initializing phase during the constant setting part so it can only look for things that are already initialized...
    This is 100% correct.
  10. Notice that Module.is_a?(Class) and Class.is_a?(Module) yet Module != Class

    Funny, right?
  11. Why would that be?
  12. Grem said:
    Why would that be?
    Because there are different kinds of equality in Ruby.
  13. I was more interested in the structural reason behind it. I know about == and === and all of the weird things those can do, but maybe it's just late but I can't really wrap my head around why Zeriab's situation works.

    If Module.is_a?(Class), then that means that Module is an instance of Class or is an instance of a class that has Class as one of its superclasses. Whereas if Class.is_a?(Module), then that means that Class is an instance of Module or is an instance of a class that has Module as one of its superclasses. This doesn't make sense to me, how would you even declare that?

    Unless Class and Module redefine #is_a?, but why would they do that?
  14. Grem said:
    I was more interested in the structural reason behind it. I know about == and === and all of the weird things those can do, but maybe it's just late but I can't really wrap my head around why Zeriab's situation works.

    If Module.is_a?(Class), then that means that Module is an instance of Class or is an instance of a class that has Class as one of its superclasses. Whereas if Class.is_a?(Module), then that means that Class is an instance of Module or is an instance of a class that has Module as one of its superclasses. This doesn't make sense to me, how would you even declare that?

    Unless Class and Module redefine #is_a?, but why would they do that?
    The way I understand it is all classes in Ruby are instances of the class Class, so the classes you make are all instances of class Class and all of the built-in classes are instances of class Class. So the reason why Module.is_a?(Class) is true is because Module itself is an instance of class Class. The class Class also has a superclass of Module, so Class.is_a?(Module) is also true because Class is an instance of class Class which has a superclass of Module. 

    So, yea... It's all a little circular.
  15. That's pretty interesting. It still seems weird to me since I thought Ruby was more internally "proper" than that -- it's so OO, I didn't think stuff like Module being a superclass of Class while being an instance of Class happened.

    I actually did learn that if a class is mixed in with a module, then #is_a? will return true for that mixed-in module. So if Class somehow has Module mixed-in with it, then Class.is_a?(Module) will return true, even if Class isn't an actual descendent of Module. But if Module isn't an actual module... hm. You know I have the Ruby book, I should just look this up at some point.