Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module-level @@-variables #3148

Closed
drosehn opened this issue Aug 12, 2016 · 3 comments
Closed

Module-level @@-variables #3148

drosehn opened this issue Aug 12, 2016 · 3 comments

Comments

@drosehn
Copy link

drosehn commented Aug 12, 2016

This is an offshoot of my comments in #3139 . This is mainly just to show that there was some real logical idea behind my rambling, although I consider this as just a "convenience" feature, and not something that is important. Hopefully I will sound a little less crazy than I did last night.

Sample program:

module SimpleTest
    @@last_thing : String = "-none-"
    @@print_count : Int32 = 0

    class OneThing
        def initialize
            puts "    - Created One"
            # -- @@last_thing = self.class.to_s         # Obviously wrong!
            SimpleTest.last_thing = self.class.to_s     # Works
            # $last_thing = self.class.to_s             # '$' as convenient shorthand
        end
    end

    class OtherThing
        @@another_count : Int32 = 0

        def initialize
            @@another_count += 1
            printf "    - Created anOther #%d\n", @@another_count
            # -- @@last_thing = self.class.to_s         # Obviously wrong!
            SimpleTest.last_thing = self.class.to_s
        end
    end

# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#   These "Module-methods" are needed so that code within
#   classes can reference the Module-level @@variables
#   (instead of getting the class-level @@variables).
def self.last_thing 
    return @@last_thing
end
protected def self.last_thing=(newval : String)
    @@last_thing = newval
end

# - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#   --  "Main" program

def self.print_last
    @@print_count += 1
    printf "last #%d = %s\n", @@print_count, @@last_thing
end

print_last

fake1 = OneThing.new
print_last

fake2 = OtherThing.new
print_last

fake3 = OtherThing.new
print_last

fake4 = OneThing.new
printf "\nFinal last = %s\n", @@last_thing

end

#   Cannot reference @@last_thing here, but we can
#   reference SimpleTest.last_thing unless that
#   module-level method was declared as 'private'
#   or 'protected'.
printf "And then outside the module:\n      last = %s\n",
    SimpleTest.last_thing

which produces:

last #1 = -none-
    - Created One
last #2 = SimpleTest::OneThing
    - Created anOther #1
last #3 = SimpleTest::OtherThing
    - Created anOther #2
last #4 = SimpleTest::OtherThing
    - Created One

Final last = SimpleTest::OneThing
And then outside the module:
      last = SimpleTest::OneThing

What I was trying to say was that maybe crystal could support '$' as a convenient shorthand for "@@-variable tied to the current module", to make it easy for classes to reference module-level @@-variables. I now realize that the class_property, class_setter, and class_getter macros would address the same thing that I was trying to address with '$', but at the time I didn't understand what @jhass meant by those macros. I guess one difference would be that '$' would reference the method-level variable directly, instead of going through a method to access it. Also, '$' would only work for methods inside of the Module, instead of creating module-level methods that (by default) would be visible outside of that module.

And in a related (and possibly ignorant) question: the variable 'self' can be used to reference the current class or the current method, depending on context. Is there any variable which could be used to reference "the current module", without explicitly naming that module? Something such that I could have said self_module.last_thing = self.class.to_s inside of OneThing.initialize, and it would have worked the same as SimpleTest.last_thing = self.class.to_s?

One more question. I have not learned about macros yet. For the macros that @jhass is suggesting, will the following work:

protected class_setter    answer : Int32

?

@jhass
Copy link
Member

jhass commented Aug 12, 2016

I think having to explicitly reference the module is a good thing. It should be clear who owns the global state, everywhere.

Conflating two different concepts ($~ style pseudo globals and this) into the same sigil is also something I rather dislike, see #1395

protected before the macro should work afaik.

@ozra
Copy link
Contributor

ozra commented Aug 13, 2016

It would be to confusing. Clarity saves the day.
As for "not going through the method": If there's nothing but an access happening in the method, it will be optimized to a direct access in LLVM. Then, if one day, you parallelize your program; now all you need to do is add locking to the method and it just keeps working.

@asterite
Copy link
Member

The snippet is correct, class/instance variables are only looked up in the immediate type, not in their namespace if not found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants