0

I am seeing a lot of different preferences around the following:

class Foo
  VAR = "Some string".freeze

  # or 

  def self.var
    "Some String"
  end
end

both can be accessed the same way:

Foo::VAR 
#=> "Some String"

Foo::var
#=> "Some String"

but you can also do Foo.var to get the same string if it was a method. defining it as a variable feels like you break the power of encapsulation that OO gives us. I see however a lot of strings/magic numbers being stored in variables inside class's, this seems like a more common practice.

I am not sure which is right.

EDIT Sorry, my question is a little confusing. I wanted to find out if it's better to store strings in methods vs storing them in variables for a class. Me explaining how to call the methods confused the question.

legendary_rob
  • 12,792
  • 11
  • 56
  • 102
  • 1
    `VAR` is a constant. `var` is a class method. Class methods might be called with any syntax (a double colon _and_ a dot.) Everything is right. I vote to close this question. – Aleksei Matiushkin Jan 04 '18 at 09:18
  • 2
    It's more idiomatic to use `Foo.var` instead of `Foo::var`. As noted in the [documentation](http://ruby-doc.org/core-2.5.0/doc/syntax/calling_methods_rdoc.html#label-Receiver): _"You may also use `::` to designate a receiver, but this is rarely used due to the potential for confusion with `::` for namespaces."_ – Stefan Jan 04 '18 at 09:36
  • Sorry so the question is not which is better `Foo::VAR` / `Foo::var` but rather storing the strings in variables vs methods. – legendary_rob Jan 04 '18 at 09:46
  • 2
    The answer to that would be: store it anywhere you find more funny. – Aleksei Matiushkin Jan 04 '18 at 09:48
  • The main reason for the question I am getting told that storing it in a var is fundamentally bad: "Keep constants for classes and modules, please. Why do we have to scroll to see what this value is from the method? Ruby constants does not work like java or c# where it replaces the text in compile time, it actually adds it to the class instance (if i remember correctly). There is no performance or reusability win here, only more scrolling and the temptation to use this somewhere else instead of writing more OO code." I just wanted to confirm that. – legendary_rob Jan 04 '18 at 09:59
  • @TheLegend This is a heavily opinion-based question, so I cannot really answer it objectively. There are arguments for writing code in different ways, in different scenarios. For example, maybe a string is sometimes a "constant" and other times a computed value; and you'd like to provide a consistent interface for many classes? Neither option is, in my opinion, **"fundamentally bad"** as you say. To see another side of the argument, I recommend the following screencast: http://www.virtuouscode.com/2012/10/01/barewords/ – Tom Lord Jan 04 '18 at 10:10
  • Show an example of storing a value in a variable. – sawa Jan 04 '18 at 10:43
  • 2
    _"defining it as a variable [...]"_ – you don't define it as a variable. `@@var` would be a variable, `VAR` is a constant. – Stefan Jan 04 '18 at 10:43
  • @Stefan sure, constant being a kind of variable. `@var` is an instance variable `@@var` a class variable. it's just a placeholder for something. – legendary_rob Jan 04 '18 at 14:26

2 Answers2

1

Based on your question, storing immutable string in a CONSTANT makes more sense. Storing in a CONSTANT serves the basic purpose i.e. a constant which is available for all in your lexical scope(s).

Personally, storing "Some String" in a method is waste of resource as every-time self.var is called then we are initialising the receivers' again which in this scenario is not ideal. I say this as in Ruby Scope Gate plays a huge role and due to its dynamic nature and every-time you access a class and its methods you are entering a new scope. There is a similar question being asked here too.

RajG
  • 832
  • 2
  • 15
  • 26
0

First, using a constant would guarantee that subclasses use not only the same string but also the same object.

  class Bar < Foo; end
  Foo::VAR.object_id == Bar::VAR.object_id # => true

And second, calling a class method with :: syntax is quite confusing, convention is to use . (see https://github.com/bbatsov/ruby-style-guide#double-colons)

So i would promote constant use

  • `class Foo; def self.var; "str".frozen; end; end; class Bar < Foo; end` also guarantees both use the same object. I don’t see any reasoning in your answer. Conventions are just conventions, you like that, I like this, it’s too opinion based (and biased,) that should never be promoted as an answer. – Aleksei Matiushkin Jan 04 '18 at 09:20
  • indeed using a frozen value returned by a class method, object id is the same for subclasses. (the question should be modified then). btw you have a typo i think you meant `"str".freeze` – bixente.bvd Jan 04 '18 at 09:47