I was playing around in irb, and noticed one cannot do
5 * "Hello".
Error
String can't be coerced into Fixnum
However "Hello"*5 provided "HelloHelloHelloHelloHello" as expected.
What is the exact reason for this? I've been looking around in the doc's and could not find the exact reason for this behavior. Is this something the designers of ruby decided?
Basically, you are asking "why is multiplication not commutative"? There are two possible answers for this. Or rather one answer with two layers.
The basic principle of OO is that everything happens as the result of one object sending a message to another object and that object responding to that message. This "messaging" metaphor is very important, because it explains a lot of things in OO. For example, if you send someone a message, all you can observe is what their response is. You don't know, and have no idea of finding out, what they did to come up with that response. They could have just handed out a pre-recorded response (reference an instance variable). They could have worked hard to construct a response (execute a method). They could have handed the message off to someone else (delegation). Or, they just don't understand the message you are sending them (NoMethodError).
Note that this means that the receiver of the message is in total control. The receiver can respond in any way it wishes. This makes message sending inherently non-commutative. Sending message foo to a passing b as an argument is fundamentally different from sending message foo to b passing a as an argument. In one case, it is a and only a that decides how to respond to the message, in the other case it is b and only b.
Making this commutative requires explicit cooperation between a and b. They must agree on a common protocol and adhere to that protocol.
In Ruby, binary operators are simply message sends to the left operand. So, it is solely the left operand that decides what to do.
So, in
'Hello' * 5
the message * is sent to the receiver 'Hello' with the argument 5. In fact, you can alternately write it like this if you want, which makes this fact more obvious:
'Hello'.*(5)
'Hello' gets to decide how it responds to that message.
Whereas in
5 * 'Hello'
it is 5 which gets to decide.
So, the first layer of the answer is: Message sending in OO is inherently non-commutative, there is no expectation of commutativity anyway.
But, now the question becomes, why don't we design in some commutativity? For example, one possible way would be to interpret binary operators not as message sends to one of the operands but instead message sends to some third object. E.g., we could interpret
5 * 'Hello'
as
*(5, 'Hello')
and
'Hello' * 5
as
*('Hello', 5)
i.e. as message sends to self. Now, the receiver is the same in both cases and the receiver can arrange for itself to treat the two cases identically and thus make * commutative.
Another, similar possibility would be to use some sort of shared context object, e.g. make
5 * 'Hello'
equivalent to
Operators.*(5, 'Hello')
In fact, in mathematics, the meaning of a symbol is often dependent on context, e.g. in ℤ, 2 / 3 is undefined, in ℚ, it is 2/3, and in IEEE754, it is something close to, but not exactly identical to 0.333…. Or, in ℤ, 2 * 3 is 6, but in ℤ|5, 2 * 3 is 1.
So, it would certainly make sense to do this. Alas, it isn't done.
Another possibility would be to have the two operands cooperate using a standard protocol. In fact, for arithmetic operations on Numerics, there actually is such a protocol! If a receiver doesn't know what to do with an operand, it can ask that operand to coerce itself, the receiver, or both to something the receiver does know how to handle.
Basically, the protocol goes like this:
you call 5 * 'Hello'
5 doesn't know how to handle 'Hello', so it asks 'Hello' for a coercion. …
… 5 calls 'Hello'.coerce(5)
'Hello' responds with a pair of objects [a, b] (as an Array) such that a * b has the desired result
5 calls a * b
One common trick is to simply implement coerce to flip the operands, so that when 5 retries the operation, 'Hello' will be the receiver:
class String
def coerce(other)
[self, other]
end
end
5 * 'Hello'
#=> 'HelloHelloHelloHelloHello'
Okay, OO is inherently non-commutative, but we can make it commutative using cooperation, so why isn't it done? I must admit, I don't have a clear-cut answer to this question, but I can offer two educated guesses:
coerce is specifically intended for numeric coercion in arithmetic operations. (Note the protocol is defined in Numeric.) A string is not a number, nor is string concatenation an arithmetic operation.
We just don't expect * to be commutative with wildly different types such as Integer and String.
Of course, just for fun, we can actually observe that there is a certain symmetry between Integers and Strings. In fact, you can implement a common version of Integer#* for both String and Integer arguments, and you will see that the only difference is in what we choose as the "zero" element:
class Integer
def *(other)
zero = case other
when Integer then 0
when String then ''
when Array then []
end
times.inject(zero) {|acc, _| acc + other }
end
end
5 * 6
#=> 30
5 * 'six'
#=> 'sixsixsixsixsix'
5 * [:six]
#=> [:six, :six, :six, :six, :six, :six]
The reason for this is, of course, that the set of strings with the concatenation operation and the empty string as the identity element form a monoid, just like arrays with concatenation and the empty array and just like integers with addition and zero. Since all three are monoids, and our "multiplication as repeated addition" only requires monoid operations and laws, it will work for all monoids.
Note: Python has an interesting twist on this double-dispatch idea. Just like in Ruby, if you write
a * b
Python will re-write that into a message send:
a.__mul__(b)
However, if a can't handle the operation, instead of cooperating with b, it cooperates with Python by returning NotImplemented. Now, Python will try with b, but with a slight twist: it will call
b.__rmul__(a)
This allows b to know that it was on the right side of the operator. It doesn't matter much for multiplication (because multiplication is (usually but not always, see e.g. matrix multiplication) commutative), but remember that operator symbols are distinct from their operations. So, the same operator symbol can be used for operations that are commutative and ones that are non-commutative. Example: + is used in Ruby for addition (2 + 3 == 3 + 2) and also for concatenation ('Hello' + 'World' != 'World' + 'Hello'). So, it is actually advantageous for an object to know whether it was the right or left operand.
This is because that operators are also methods(Well there are exceptions as Cary has listed in the comments which I wasn't aware of).
For example
array << 4 == array.<<4
array[2] == array.[](2)
array[2] ='x' == array.[] =(2,'x')
In your example:
5 * "Hello" => 5.*("Hello")
Meanwhile
"hello" *5 => 5.*("hello")
An integer cannot take that method with a string param
If you ever dabble around in python try 5*hello and hello*5, both work. Pretty interesting that ruby has this feature to be honest.
Well, as Muntasir Alam has already told that Fixnum does not has a method named * which takes a string as argument. So, 5*"Hello" produces that error.But, to have fun we can actually achieve 5*"Hello" this by adding that missing method to the Fixnum class.
class Fixnum # open the class
def * str # Override the *() method
if str.is_a? String # If argument is String
temp = ""
self.times do
temp << str
end
temp
else # If the argument is not String
mul = 0
self.times do
mul += str
end
mul
end
end
end
now
puts 5*"Hello" #=> HelloHelloHelloHelloHello
puts 4*5 #=> 20
puts 5*10.4 #=> 52.0
Well, that was just to show that the opposite is also possible. But that will bring a lot of overhead. I think we should avoid that at all cost.
Related
I have a few test cases that I need to write a method for, and how they execute the method is like this:
Planets with: aString , anotherString
Where "Planets" is a class and "with:" is a class method. But my confusion is in the way that arguments are given, because I was under the impression that methods with multiple arguments get executed like "methodName: arg1 Arg2: arg2", but in here the two arguments are separated by comma. Can somebody explain this to me please?
It has to do with the order of precedence for messages. Unary messages get handled first, then binary messages, and finally keyword messages.
Unary messages have no arguments (new, sqrt, isPrime)
Binary messages go between two objects (like a + or in your case the ,).
Keyword messages end in a colon (like with:) and sometimes there is more than one (like to: do:)
The binary message , (concatenate two strings) is processed first because it has a higher precedence. Then the keyword message with: is processed after because it has a lower precedence. Messages inside of parentheses automatically get the highest precedence and are evaluated first. When there is a "tie" (multiple messages have the same precedence), they are evaluated left to right.
One weird thing about Smalltalk is that + - * / all have the same binary message precedence. So 8 + 2 * 4 evaluates to 40 not 16 like you might expect.
Most likely, the class method #with: receives a String as its only argument. This means that #with: is a keyword message with arity 1. In the expression
Planets with: aString , anotherString
there are two messages: (1) the message with selector #with: and (2) the message with selector #,. The latter has a receiver aString and an argument anotherString. This is a binary message with arity 1 too.
In fact, one could equally write
Planets with: (aString , anotherString)
to emphasize the role of argument played by the parenthesized expression. We usually don't do that because precedence rules make it unnecessary.
Now note that in the declaration of the method with selector#with: you would have
Planets class >> #with: aString
"some code here"
But one thing is the declaration of a method and another its invocation, in your case
Plantes with: aString , anotherString
is an expression aimed at sending the message #with: to Planets with an argument that happens to be the concatenation of two strings.
In sum, when you declare/define the method the argument is aString, but when you invoke it (i.e., when you send the message) the argument is anything that evaluates to a String.
As a side note I would indicate that Planets isn't a good name for a class. In fact, class names are usually in singular, as they represent a concept, not a collection of instances of said concept.
In Ruby, there is Object#freeze, which prevents further modifications to the object:
class Kingdom
attr_accessor :weather_conditions
end
arendelle = Kingdom.new
arendelle.frozen? # => false
arendelle.weather_conditions = 'in deep, deep, deep, deep snow'
arendelle.freeze
arendelle.frozen? # => true
arendelle.weather_conditions = 'sun is shining'
# !> RuntimeError: can't modify frozen Kingdom
script = 'Do you want to build a snowman?'.freeze
script[/snowman/] = 'castle of ice'
# !> RuntimeError: can't modify frozen String
However, there is no Object#unfreeze. Is there a way to unfreeze a frozen kingdom?
Update: As of Ruby 2.7 this no longer works!
Yes and no. There isn't any direct way using the standard API. However, with some understanding of what #freeze? does, you can work around it. Note: everything here is implementation details of MRI's current version and might be subject to change.
Objects in CRuby are stored in a struct RVALUE.
Conveniently, the very first thing in the struct is VALUE flags;.
All Object#freeze does is set a flag, called FL_FREEZE, which is actually equal to RUBY_FL_FREEZE. RUBY_FL_FREEZE will basically be the 11th bit in the flags.
All you have to do to unfreeze the object is unset the 11th bit.
To do that, you could use Fiddle, which is part of the standard library and lets you tinker with the language on C level:
require 'fiddle'
class Object
def unfreeze
Fiddle::Pointer.new(object_id * 2)[1] &= ~(1 << 3)
end
end
Non-immediate value objects in Ruby are stored on address = their object_id * 2. Note that it's important to make the distinction so you would be aware that this wont let you unfreeze Fixnums for example.
Since we want to change the 11th bit, we have to work with the 3th bit of the second byte. Hence we access the second byte with [1].
~(1 << 3) shifts 1 three positions and then inverts the result. This way the only bit which is zero in the mask will be the third one and all other will be ones.
Finally, we just apply the mask with bitwise and (&=).
foo = 'A frozen string'.freeze
foo.frozen? # => true
foo.unfreeze
foo.frozen? # => false
foo[/ (?=frozen)/] = 'n un'
foo # => 'An unfrozen string'
No, according to the documentation for Object#freeze:
There is no way to unfreeze a frozen object.
The frozen state is stored within the object. Calling freeze sets the frozen state and thereby prevents further modification. This includes modifications to the object's frozen state.
Regarding your example, you could assign a new string instead:
script = 'Do you want to build a snowman?'
script.freeze
script = script.dup if script.frozen?
script[/snowman/] = 'castle of ice'
script #=> "Do you want to build a castle of ice?"
Ruby 2.3 introduced String#+#, so you can write +str instead of str.dup if str.frozen?
frozen_object = %w[hello world].freeze
frozen_object.concat(['and universe']) # FrozenError (can't modify frozen Array)
frozen_object.dup.concat(['and universe']) # ['hello', 'world', 'and universe']
As noted above copying the variable back into itself also effectively unfreezes the variable.
As noted this can be done using the .dup method:
var1 = var1.dup
This can also be achieved using:
var1 = Marshal.load(Marshal.dump(var1))
I have been using Marshal.load(Marshal.dump( ... )
I have not used .dup and only learned about it through this post.
I do not know what if any differences there are between Marshal.load(Marshal.dump( ... )
If they do the same thing or .dup is more powerful, then stylistically I like .dup better. .dup states what to do -- copy this thing, but it does not say how to do it, whereas Marshal.load(Marshal.dump( ... ) is not only excessively verbose, but states how to do the duplication -- I am not a fan of specifying the HOW part if the HOW part is irrelevant to me. I want to duplicate the value of the variable, I do not care how.
Here is code
def tmp
a = ancestors.first(ancestors.index(ActiveRecord::Base))
b = a.sum([]) { |m| m.public_instance_methods(false) |
m.private_instance_methods(false) |
m.protected_instance_methods(false) }
b.map {|m| m.to_s }.to_set
end
I thought | is bitwise OR operator. So how come b contains non boolean values?
It would have helped if you said what your code was supposed to do, but I think I finally got it. The | that you have is not an OR at all, neither bitwise nor logical. It is an array union operation. Look it up under Array rubydoc. It takes Array arguments and gives an Array result consisting of all elements that are in either array.
Since pretty much everything in Ruby is an object (aside from blocks, not relevant here), there are no absolute "operators" except for simple assignment. Every operator is in fact a method defined on some class, and therefore contextual.
Also, as someone rightly pointed out (deleted now), bitwise OR deals with integers, not booleans: 7 | 12 == 15. Logical or || deals with boolean values, but it too can return a non-boolean, since strictly speaking everything except for nil and false is true. Thus, 7 || 12 returns 7, not true (which is still equivalent to true in most contexts).
UPDATE: I've overlooked the fact that || and &&, when used on a Boolean object, can not actually be defined in Ruby, because of their short-circuit semantics. This nevertheless does not change the fact that they behave like methods of Boolean.
I play around with arrays and hashes quite a lot in ruby and end up with some code that looks like this:
sum = two_dimensional_array.select{|i|
i.collect{|j|
j.to_i
}.sum > 5
}.collect{|i|
i.collect{|j|
j ** 2
}.average
}.sum
(Let's all pretend that the above code sample makes sense now...)
The problem is that even though TextMate (my editor of choice) picks up simple {...} or do...end blocks quite easily, it can't figure out (which is understandable since even I can't find a "correct" way to fold the above) where the above blocks start and end to fold them.
How would you fold the above code sample?
PS: considering that it could have 2 levels of folding, I only care about the outer consecutive ones (the blocks with the i)
To be honest, something that convoluted is probably confusing TextMate as much as anyone else who has to maintain it, and that includes you in the future.
Whenever you see something that rolls up into a single value, it's a good case for using Enumerable#inject.
sum = two_dimensional_array.inject(0) do |sum, row|
# Convert row to Fixnum equivalent
row_i = row.collect { |i| i.to_i }
if (row_i.sum > 5)
sum += row_i.collect { |i| i ** 2 }.average
end
sum # Carry through to next inject call
end
What's odd in your example is you're using select to return the full array, allegedly converted using to_i, but in fact Enumerable#select does no such thing, and instead rejects any for which the function returns nil. I'm presuming that's none of your values.
Also depending on how your .average method is implemented, you may want to seed the inject call with 0.0 instead of 0 to use a floating-point value.
A class I am taking currently requires us to do all of our coding in smalltalk (it's a Design class). On one of our projects, I am looking to do some things, and am having a tough time finding how to do them. It seems that what most people do is modify their own version of smalltalk to do what they need it to do. I am not at liberty to do this, as this would cause an error on my prof's computer when he doesn't have the same built-in methods I do.
Here's what I'm looking to do:
Random Numbers. I need to create a random number between 1 and 1000. Right now I'm faking it by doing
rand := Random new.
rand := (rand nextValue) * 1000.
rand := rand asInteger.
This gives me a number between 0 and 1000. Is there a way to do this in one command? similar to
Random between: 0 and: 1000
And/Or statements. This one bugs the living daylights out of me. I have tried several different configurations of
(statement) and: (statement) ifTrue...
(statement) and (statement) ifTrue...
So I'm faking it with nested ifTrue statements:
(statement) ifTrue:[
(statement) ifTrue:[...
What is the correct way to do and/or and Random in smalltalk?
The problem is that
(expr) and: (expr) ifTrue: aBlock
is parsed as the method and:ifTrue: If you look at the Boolean class (and either True or False in particular), you notice that ifTrue: is just a regular method, and that no method and:ifTrue: exists - however, plain and: does. So to make it clear that these are two messages, write
((expr) and: (expr)) ifTrue: aBlock
For longer boolean combinations, notice that there are also methods and:and: and and:and:and: implemented.
(1 to: 1000) atRandom
If you're using VisualWorks, and: takes a block as an argument, so you'd write:
(aBoolean and: [anotherBoolean]) ifTrue: [doSomething].
There's also &, which does not take a block as argument,
aBoolean & anotherBoolean ifTrue:[doSomething].
The difference is and: only evaluates what's in the block if the first bool is true (similar to java), while & always evaluates both.
Thus and: comes in handy if the second condition is computationally expensive, or if it includes state alterations which should only happen when the first condition is true. (that's usually a bad design though).
As for the Random, as long as you deliver your custom method, Random >> between: and: as well as the rest of your code, it runs fine on your professors computer. How to do that specifically, depends on the format in which you are supposed to deliver the assignment.
As for the Random issue: it depends on what ST version you use. In Squeak 3.9, there is Random>>#nextInt:, which is documented as "Answer a random integer in the interval [1, anInteger].". Its implementation reads
(self next * anInteger) truncated + 1
So I have two comments here:
You should really learn to use the class browser. This can answer the (frequent) questions "what messages can I send to objects of class X"
It is common, in ST, to add new methods to existing classes. So if you want Random to have between:and:, just add it, e.g. as
between: low and: high
^(self next * (high-low+1)) truncated + low
To put it simply, without knowing the Smalltalk dialect, I can only give a general answer. The way you stated the random question, yes that's the only way to do it if your professor needs a generic answer.
As for the and/or statements question,
And/Or statements. This one bugs the living daylights out of me. I have tried several different configurations of
(statement) and: (statement) ifTrue...
(statement) and (statement) ifTrue...
What you want to try is:
(statement) and: [statement] ifTrue: [ ... ]
note the brackets, the and: method takes a block as an argument.
To create several random integers between 1 and 1000
First create a random number series. Do this just once.
Then create a new random number by taking the next number from the series. Repeat as necessary.
aRandomSeries := Random new .
"Seed a new series of random numbers"
aRandomInt := aRandomSeries newInt: 1000 .
"generate a random integer between 0 and 1000"
anotherRandomInt := aRandomSeries newInt: 1000 .
"generate another random integer between 0 and 1000"
Logical operations
aBoolean will respond to and: and or:. They both take block arguments.
Here is how they work.
and: alternativeBlock
If the receiver is true, answer the value of alternativeBlock; otherwise answer false without evaluating alternativeBlock.
or: alternativeBlock
If the receiver is false, answer the value of alternativeBlock; otherwise answer true without evaluating alternativeBlock.
e.g.
( 3 > 2 ) or: [ 3 < 4 ] ifTrue: [ ]
aBoolean and: [ anotherBoolean ] ifFalse: [ ]
However, Squeak and Pharo Smalltalks will both accept an argument in parentheses ( )
Dolphin Smalltalk will not, and strictly requires the standard Smalltalk syntax of a block argument.
Other related methods:
& an AND that does not require a square bracketted (i.e. block) argument
| an OR that does not require a square bracketted (i.e. block) argument
& and | work in Amber, Cuis, Gnu, Pharo, Squeak, VisualAge and VisualWorks Smalltalks.
Squeak Smalltalk also provides:
and:and: }
and:and:and: } These take multiple block arguments
and:and:and:and }
or:or: }
or:or:or: } These take multiple block arguments
or:or:or:or: }