Using the example of 2 hashes hash={:fruit=>"Apple", :vegetable="Cucumber"} and hash={"fruit"=>"Apple", "vegetable"="Cucumber"} . Tell us what is the difference between these entities and where symbol is used.

3 answers 3

A variable is a named memory area, it contains a name and a value, the value can be changed.

A string is simply a region of memory that you can modify.

A symbol is just a name. This construct is very popular in functional languages ​​and is usually called an atom — something indivisible and unchanging. For example, white color,: white - there is no need for a value, there is no need for a change - white color will remain white so that it does not occur. This is a character in ruby.

Characters are used where no value is required, for example, for enumerations, passing the name of a key or method. Strings and characters can be converted into each other, but these are different classes.

    I think that it is worth highlighting the question from a technical point of view (I will answer the question how?, But not the question why? ). First of all, a general fact: any value in Ruby is an object. And the object is uniquely identified by a link to it. You can get the value derived from the reference from the объект.object_id .

    (where explicitly stated, examples in Ruby 2.2.3)

    • With the string, everything is more or less clear: this is simply a reference to the buffer of a finite (but changeable if necessary) length in which characters are stored.

      • The contents of this buffer can be changed at your discretion (i.e., the lines are mutable ), and therefore keeping the link to the line in one place, you cannot be sure that when you next look at the link there will be the same thing that was before.
      • The same strings are usually * different objects:

         ''.object_id == ''.object_id # => false 
    • Symbols are a small wrapper over lines , whose objects are stored in a different way in memory .

      • The storage method is such that a symbol with a specific name (string), when used within the same Ruby process, will be the same object anywhere. This allows you to very quickly compare characters for equality : it is enough to compare references to them, even not looking at its string, that is, to find out if it is not the same object. This is O(1) , whereas string comparison is O(object.length) .
      • This method of storage is called internment ; all character strings in Ruby are interned. In Ruby, String#intern and String#to_sym synonyms. .to_sym , in my opinion, is preferable, .to_sym reflects the real type of the return value.
      • The principle of operation is well described in the documentation for String intern() in Java : a class somewhere within itself supports a global set of all interned values. When an interned value is requested, either an equal value from the set is taken, or the requested value is copied (!) Into the set and returned.
      • Once all the characters, once appeared, never disappeared, the garbage collector did not touch them even if they were no longer used. Therefore, it was dangerous to make characters from strings arriving from the user: by sending various strings in tons, it was possible to take a bunch of RAM from the characters, causing its shortage and a drop in the process. Bang bang This is fixed in Ruby 2.2.

    meanwhile on the horizon ...

    * ... but this may change over time. Ruby 2.3 introduces the option to freeze all string literals in code. In Ruby 3.0, it will be enabled by default.

    Freezing an object makes it impossible to change it (a mutation, i.e., the object becomes immutable). The object can be frozen using the freeze method. And as applied to strings, the interpreter can apply an interesting optimization: represent the same literals with the same object.

     ''.object_id == ''.object_id # => true # хоть вроде сравнение такое же! 

    This is logical: the only danger of a mutable object is that its contents can be suddenly changed somewhere very far away. In an amicable way, where it is critical, the object should be frozen. This can be done explicitly in older versions or when the freezing option is turned off, and the effect will be reproduced:

     ''.freeze.object_id == ''.freeze.object_id # => true 

    But freezing and interning are different things , unlike characters that are not always the same, frozen lines are the same object:

     a = '' a.freeze # он деструктивный, замораживает тот объект, на котором вызван b = ''.freeze a.object_id == b.object_id # => false 

      As @cheops rightly said, String is a region of memory that can be edited, etc. Symbols can be perceived as constants, the values ​​of which are not explicitly indicated, but serve to avoid magic numbers. Like the enum .