Are There Primitive Types in Ruby

Are there primitive types in Ruby?

A core principle of Ruby is that all data should be represented as objects. Other languages such as Smalltalk follow a similar paradigm.

The benefit of this design is that it makes Ruby more elegant and easier to learn. The rules applying to objects are consistently applied to all of Ruby.

For instance, when beginners are first learning Java, the difference between the primitive type int and the wrapper class Integer can be confusing. This confusion is exacerbated by the sometimes confusing implicit conversions between the two via autoboxing.

So why would languages like Java or C# bother with primitive types? The answer is performance. Creating objects incurs additional overhead when compared with primitives.

pass reference of primitive data types to functions in ruby

Ruby doesn't pass arguments by reference:

def change(x)
x = 2 # this assigns to a local variable 'x'
end

a = 1
change(a)
a #=> 1

You could pass a mutable object instead, e.g. a hash "containing" an integer:

def change(h)
h[:x] = 2
end

h = {x: 1}
change(h)
h[:x] #=> 2

Determining type of an object in ruby

The proper way to determine the "type" of an object, which is a wobbly term in the Ruby world, is to call object.class.

Since classes can inherit from other classes, if you want to determine if an object is "of a particular type" you might call object.is_a?(ClassName) to see if object is of type ClassName or derived from it.

Normally type checking is not done in Ruby, but instead objects are assessed based on their ability to respond to particular methods, commonly called "Duck typing". In other words, if it responds to the methods you want, there's no reason to be particular about the type.

For example, object.is_a?(String) is too rigid since another class might implement methods that convert it into a string, or make it behave identically to how String behaves. object.respond_to?(:to_s) would be a better way to test that the object in question does what you want.

Size of numeric data types in Ruby

I know that Ruby has Float for real, Fixnum and Bignum for int.

This is not true.

Float does not represent real numbers, it represents floating point numbers. In fact, in the general case, representing real numbers in a physical computer is impossible, as it requires unbounded memory.

Fixnum and Bignum are not part of Ruby. Ruby only has Integer. The Ruby Specification allows different implementations to have implementation-specific subclasses, but these are then specific to that particular implementation (e.g. YARV, Opal, TruffleRuby, Artichoke, JRuby, IronRuby, MRuby, etc.), they don't have anything to do with Ruby.

In fact, even knowing the implementation is not enough, you have to know the exact version. For example, YARV had Fixnum and Bignum as subclasses in the past, but now it doesn't anymore, it only has Integer. And even back when it had them, that was still not enough, because they actually had different sizes depending on the platform.

But what about sizes of this types?

a = 1.23 // size of one Float in bytes?

b = 1 // size of one Fixnum in bytes?

c = 2**65 // = size of one Bignum in bytes?

I am trying to find a standard or specification

Here is what the ISO/IEC 30170:2012 Information technology — Programming languages — Ruby specification has to say on the matter [bold emphasis mine]:

15.2.8 Integer

15.2.8.1 General description

Instances of the class Integer represent integers. The ranges of these integers are unbounded. However the actual values computable depend on resource limitations, and the behavior when the resource limits are exceeded is implementation-defined.

[…]

Subclasses of the class Integer may be defined as built-in classes. In this case:

  • The class Integer shall not have its direct instances. Instead of a direct instance of the class Integer, a direct instance of a subclass of the class Integer shall be created.
  • Instance methods of the class Integer need not be defined in the class Integeritself if the instance methods are defined in all subclasses of the class Integer.
  • For each subclass of the class Integer, the ranges of the values of its instances may be bounded.

The ISO Ruby Language Specification does not mandate any particular size or representation for Integers, nor does it specify any methods for querying this information.

15.2.9 Float

15.2.9.1 General description

Instances of the class Float represent floating-point numbers.
The precision of the value of an instance of the class Float is implementation-defined; however, if the underlying system of a conforming processor supports IEC 60559, the representation of an instance of the class Float shall be the 64-bit double format as specified in IEC 60559, 3.2.2.

The ISO Ruby Language Specification does not mandate any particular size or representation for Floats, unless the underlying system supports ISO/IEC 60559, in which case the representation must be as an ISO/IEC 60559 binary64 double float. The ISO Ruby Language Specification does not specify any methods for querying this information.

The ruby/spec does not say anything about the size or precision of Float. In fact, it is very careful to not say anything. For example, if you look at the spec for Float#prev_float, you can see that they are very careful to specify the behavior of Float#prev_float without ever referring to the actual precision.

The ruby/spec for Integer#size does say something about the sizes of specific machine integers in bytes. However, unfortunately, ruby/spec is kind of a mixture between specifications for the behavior of the Ruby Programming Language and the behavior of the YARV Ruby Implementation. I have the feeling that this spec is more like the latter.

For example, the cutoff point between fixnums and bignums in YARV is 231 on 32 bit platforms and 263 on 64 bit platforms, but on JRuby, it is 264 on both 32 bit and 64 bit platforms (and I think TruffleRuby is the same). So, 3000000000 will be a bignum on 32 bit YARV, but a fixnum on 64 bit YARV and JRuby, and 10000000000000000000 will be a bignum on both 32 bit and 64 bit YARV, but will be a fixnum even on 32 bit JRuby. For Opal, I think the cutoff point is different again, I think it is 253. Other implementations may not even distinguish between fixnums and bignums at all, or they may have three or more different kinds of integers.

Also, it is very important to remember that this spec only specifies the return value of the method Integer#size. Nowhere does it say that this is actually how an Integer must be represented in memory.

By the way, you may be confused why I am talking about fixnums and bignums in YARV, when I said above that Fixnum and Bignum have been removed from YARV. Well, the reason is that the separate classes have been removed, but the optimization is still there. Which is another thing: the ISO Ruby Language Specification says that you are allowed to have implementation-specific subclasses of Integer, but it doesn't say what those classes are for. Neither does the ISO Ruby Language Specification force implementors to have optimized implementations for their subclasses, nor does it force implementors to have subclasses for their implementation-specific optimizations.

Compare that to YARV's flonums which are an optimized representation of 62 bit Floats, but they don't have their own class.

So, in (not so) short: the ISO Ruby Language Specification does not say anything about the sizes of Integers, but it does say that if the underlying system supports ISO/IEC 60559, then the representation must be an ISO/IEC 60559 binary64 double float. It does, however, say nothing about the size or representation for cases where the underlying system does not support ISO/IEC 60559.

The ruby/spec is careful not to specify anything about the sizes of Floats, but it does specify the return value of the Integer#size method. It does, however, not specify that this return value must in any way correspond to how Integers are actually represented.

Here's what the RDoc for Integer#size in YARV has to say [bold emphasis mine]:

sizeint

Returns the number of bytes in the machine representation of int (machine dependent).

So, it only says that it returns the number of bytes the Integer would have in the machine representation, but not that this is necessarily the way that it is actually represented. And it clearly states that the value is machine dependent.

What does a hash without a key mean in Ruby?

A hash needs to be defined as either empty or with key, value pairs (see here). I'm guessing if you are following some sort of a tutorial, you need to fill those values in with some constants.

Usually variables in CAPS are constants, but it is possible to define a method in caps. Even so, one would need to call it explicitly with braces, as in TOKEN() and I can't think of anything that could be put inside curly braces to initialize a hash of some sort.

How can I create a primitive type to a property in neo4j using ruby?

As far as type in Cypher goes, it is inferred, not explicitly declared.

amount:'16'   // '16' is a String and '16' + '5' = '165', i.e. string concatenation
amount: 16 // 16 is an integer, 16 + 5 = 21
amount: 16.0 // 16.0 is a float
etc

Your amount value is a string, either set it to an int value or a float value as above, or compare it to another string: '16' > '15' as much as 16 > 15.

Ruby Data Types

There is a great discussion on using a Ruby :symbol vs a String in another question here.

And here's a nice discussion about the difference between the fat arrow => syntax vs colons : in Ruby.

You can quickly check that the two hashes using :symbols are equivalent to each other, which are both different from the hash using strings:

a = {"city" => "Miami", "state" => "Florida"}
b = {:city => "Miami", :state => "Florida"}
c = {city: "Miami", state: "Florida"}

a == b
=> false

a == c
=> false

b == c
=> true

Ruby immutability of strings and symbols (What if we store them in variables)

Ruby variables are references to objects, so when you send a method to a variable, the object it references is the context in which it is evaluated. It's probably more clear to look at the first image in the top rated answer (below the accepted answer) here.

So, to figure out what's going on, let's dig into the documentation a bit and see what happens with your code snippet.

Ruby's Symbol class documentation:
https://ruby-doc.org/core-2.5.0/Symbol.html

Symbol objects represent names and some strings inside the Ruby interpreter. They are generated using the :name and :"string" literals syntax, and by the various to_sym methods. The same Symbol object will be created for a given name or string for the duration of a program's execution, regardless of the context or meaning of that name. Thus if Fred is a constant in one context, a method in another, and a class in a third, the Symbol :Fred will be the same object in all three contexts.

Ruby's Object#object_id documentation:
https://ruby-doc.org/core-2.5.1/Object.html#method-i-object_id

Returns an integer identifier for obj.

The same number will be returned on all calls to object_id for a given object, and no two active objects will share an id.

So here's what's happening step-by-step:

# We create two variables that refer to the same object, :foo
var1 = :foo
var2 = :foo

var1.object_id = 2598748
var2.object_id = 2598748
# Evaluated as:
# var1.object_id => :foo.object_id => 2598748
# var2.object_id => :foo.object_id => 2598748

As discussed in the first link above, Ruby is pass-by-value, but every value is an Object, so your variables both evaluate to the same value. Since every symbol made of the same string ("foo" in this case) refers to the same object, and Object#object_id always returns the same id for the same object, you get the same id back.



Related Topics



Leave a reply



Submit