Given this script
def hash
puts "why?"
end
x = {}
x[[1,2]] = 42
It outputs the following
why?
/tmp/a.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError)
from /tmp/a.rb:6:in `<main>'
It seems that the hash function defned in the script is overriding Array#hash in that case. Since the return value of my hash method is nil and not an Integer, it throws an exception. The following script seems to confirm this
puts [1,2,3].hash
def hash
puts "why?"
end
puts [1,2,3].hash
The output is
-4165381473644269435
why?
/tmp/b.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError)
from /tmp/b.rb:6:in `<main>'
I tried looking into the Ruby source code but could not figure out why this happens. Is this behavior documented?
You're not overriding Array#hash, you're shadowing Kernel#hash by creating Object#hash:
puts method(:hash)
def hash
puts "why?"
end
puts method(:hash)
That prints:
#<Method: Object(Kernel)#hash>
#<Method: Object#hash>
Fix it so we can see more:
def hash
puts "why?"
super
end
x = {}
x[[1,2]] = 42
Now the output is:
why?
why?
And no error. Try it with x[[1,2,3,4,5,6,7]] = 42 and you'll instead see why? printed seven times. Once for each array element, since the array's hash method uses the hashes of its elements. And Integer#hash doesn't exist, it inherits its hash method from Object/Kernel, so yours gets used.
This is due to a kind of hack in Ruby top level. Have you ever wondered how this works?
def foo
end
p self
foo
class Bar
def test
p self
foo
end
end
Bar.new.test # no error
How are two totally different objects (main and a Bar) able to call foo like it's a private method call? The reason is because... it is a private method call.
When you define a method at the top level of your Ruby script, it gets included (via Object) in every object. That's why you can call top-level methods like they are global functions.
But why does this break only hash and not other common methods? def to_s;end won't break to_s, for example. The reason is because hash is recursive: most* class implementations ultimately call down to Object#hash for their implementations. By redefining that base case, you break it globally. For other methods like to_s you won't see a global change because it's way up the inheritance chain and doesn't get invoked.
* the only objects this doesn't break are a few literals that probably have hard-coded hash values e.g. [] {} "" true etc.
Related
I want to instantiate an object from a class I wrote on a different file. What I got is wrong number of arguments (given 1, expected 0) (ArgumentError)
Here is the main code
# ./lib/parking_lot
require_relative './lot.rb'
class ParkingLotInterface
def initialize(input: $stdin, output: $stdout)
#input, #output = input, output
#lot = nil
end
def prompt_input
#lot = Lot.new(10)
end
end
parking_lot_interface = ParkingLotInterface.new(input: $stdin, output: $stdout)
parking_lot_interface.prompt_input
And here is the object class
# ./lib/lot
class Lot
attr_reader :slots,
def initialize(size)
#slots = Arrays.new(size)
end
end
The error was thrown at the line where I tried to instantiate a new Lot object. Looking at the internet, people who had the same problem got told that they didn't specify def initialize in the class, or they mistyped it. However, I did what they all said and I still faced wrong number of arguments (given 1, expected 0) (ArgumentError)
What did I do wrong?
In Ruby, method definitions are expressions as well (in fact, in Ruby, everything is an expression, there are no statements), so they evaluate to an object. Method definition expressions evaluate to a Symbol denoting the name of the method that was defined.
So,
def initialize(*) end
#=> :initialize
In your code, you have a comma after attr_reader :slots, which means that you pass two arguments to attr_reader, namely the symbol :slots and the expression def initialize(…) … end. Since Ruby is a strict language, the arguments to attr_reader will be evaluated first, before attr_reader itself is executed.
So, what happens first is that the method definition expression gets evaluated. This defines a (private) method named initialize. It also evaluates to the symbol :initialize.
Next, the expression attr_reader :slots, :initialize gets evaluated, which defines two methods named slots and initialize, thus overwriting the method you just defined. Note that this will print a warning:
lot.rb:3: warning: method redefined; discarding old initialize
lot.rb:5: warning: previous definition of initialize was here
You should always read the warnings, the Ruby developers don't spend the hard work putting them in just for the fun of it!
The solution is to remove the comma telling Ruby to look for a second argument.
There is a second error in your code, namely that you misspelt Array within Lot#initialize.
And, there are a couple of stylistic improvements that you could make:
There is no need to pass a path and a filename extension to require_relative. It should be require_relative 'lot'.
Un-initialized instance variables evaluate to nil, so there is no need to initialize #lot to nil.
$stdin and $stdout are the default argument values of the stdin: and stdout: keyword parameters, so there is no need to pass them explicitly.
It is seldom necessary to create an array of a specific size, since Ruby arrays are dynamic and can change their size at any time.
With all this taken in to account, your code would look something like this:
# ./lib/parking_lot
require_relative 'lot'
class ParkingLotInterface
def initialize(input: $stdin, output: $stdout)
#input, #output = input, output
end
def prompt_input
#lot = Lot.new(10)
end
end
parking_lot_interface = ParkingLotInterface.new
parking_lot_interface.prompt_input
# ./lib/lot
class Lot
attr_reader :slots
def initialize(size)
#slots = Array.new(size)
# could be #slots = []
# depending on how you use `#slots` later
end
end
Delete the comma after
attr_reader :slots,
it would be
attr_reader :slots
And take a look, you are trying to instance Arrays (and must not to be in plural) on lot.rb
def initialize(size)
#slots = Arrays.new(size)
end
it would be
def initialize(size)
#slots = Array.new(size)
end
Imagine I want to write my own math operators like "+"
The simple version would be:
def plus(a,b)
return a+b
end
But this is not what the real "+" does.
I want 3.add(4) # =>7
But how do I tell ruby to take the object that I used my method on?
I tried
def add(c)
return self+c
end
But I get the error message:
:in <main>': private methodadd' called for 3:Fixnum (NoMethodError)
The problem
You defined the method:
def add(c)
return self + c
end
and attempted to use it thus:
3.add(4) #=> NoMethodError: private method `add' called for 3:Fixnum
Understanding this error message
This error message tells you exactly what the problem is. I think your problem is simply that you don't understand how Ruby invokes methods on objects.
When Ruby sees 3.add(4) it first looks at the receiver, 3, and determines:
3.class #=> Fixnum
This tells it where the method add is defined: in the class Fixnum or in one of Fixnum's ancestor's classes or modules.
So it looks for it there, doesn't find it, and issues an error message. We can confirm it's not there:
Fixnum.instance_methods.include?(:add)
#=> false
So where is add defined?
You did define it, though, so where is it? Let's find out:
method(:add).owner
#=> Object
Object.instance_methods.include?(:add)
#=> false
Object.instance_methods returns an array of all of public instance methods defined on Object and Object's ancestors. add is not among those, so we conclude add is a protected or private method:
Object.protected_instance_methods.include?(:add)
#=> false
Object.private_instance_methods.include?(:add)
#=> true
Let's try invoking that method on an instance of Object:
Object.new.add(4)
#=> NoMethodError:
# private method `add' called for #<Object:0x007fdb6a27fa68>
That makes sense, considering that Object#add is private. We can, however invoke private methods with Object#send:
Object.new.send(:add,4)
#NoMethodError: undefined method `+' for #<Object:0x007fdb6a28e068>
As an exercise, make sure you understand the steps Ruby took that led to her raising this exception (that the instance method + is not defined on Object, or equivalently, that the instance of Object does not have a method +).
By the way, where did you define add? By that, I mean what what was the value of self when you defined it? Let's see:
self #=> main
self.class #=> Object
We see that add must be defined on the class for which its receiver is an instance. (A mouthful, yes, but it's important, so make sure you understand that).
Why is Object#add private rather than public?
Consider:
def greet
puts 'hi'
end
class A
end
A.private_instance_methods.include?(:add)
#=> true
A.new.send(:greet)
#=> 'hi'
The is because A inherits greet from Object:
A.ancestors.include?(Object) #=> true
If Object#greet were public, every built-in class and every class you define would have a public instance method greet. That would result in a great deal of misery. (Suppose you had a method great and mistyped it greet!) Even the private greet could cause trouble.)
Where should add be defined?
Since add.class => Fixnum, we define it thus:
class Fixnum
def add(other)
self + other
end
end
Fixnum.instance_methods.include?(:add) #=> true
3.add(4) #=> 7
Had I included the line puts "self#{self}" after class Fixnum it would have printed "Fixnum". Salting your code with puts statements that show the value of self often helps in understanding what's going on.
One last thing:
method(:add).owner
#=> NameError: undefined method `add' for class `Object'
Why did this not return Fixnum? Since method has no explicit receiver (i.e., no xx.method), Ruby assumes the receiver to be self, which here is:
self #=> main
so she looks for the method method in self.class => Object, and you know what she finds (or, I should say, doesn't find). Instead, we need to write:
Fixnum.instance_method(:add).owner #=> Fixnum
or
3.method(:add).owner #=> Fixnum
Here 3 can of course be replaced by any instance of Fixnum.
Note I've simplified this explanation somewhat. In searching for a method, Ruby also looks in the receiver's singleton class. This is not an issue for immediate objects (numbers, symbols, true, false and nil), however, as they do not have singleton classes:
3.singleton_class #=> TypeError: can't define singleton
By contrast, for example:
[1,2].singleton_class #=> #<Class:#<Array:0x007fbcf18c01a8>>
The plus-sign (+) in ruby can be overridden pretty much like any other method (you can look for operator-overloading):
class MyOperator
attr_accessor :text
def initialize(text)
#text = text
end
def +(operand)
"#{self.text} #{operand.text}"
end
def to_s
self.text
end
end
a = MyOperator.new "Hello"
b = MyOperator.new "World"
puts (a+b)
So there is not much magic to it. But you have to be careful if the overloading the operators make sense in your context.
When you define a method, it returns a symbol with the same name as the method. Is there a point to this? Or is it just there as validation that you created it?
Like so:
def something
...
end
# => :something
IRb always displays the result of calling inspect on the value of the last expression that was evaluated. It doesn't matter whether that expression is a literal expression, a conditional expression, a message send, a class definition expression or a method definition expression.
Everything returns a value in Ruby, i.e. everything is an expression, there is no such thing as a statement in Ruby.
In the past, the return value of a method definition expression was undefined. Most Ruby implementations simply returned nil from a method definition expression, but Rubinius for example returned the CompiledMethod object for the method that was defined.
With Ruby 2.1, the return value of a method definition expression was standardized to be the Symbol corresponding to the method's name. This allows you to use the method definition expression as an argument in methods that expect the name of a method as an argument.
Some examples:
# Before Ruby 2.0:
def foo; end
private :foo
# After Ruby 2.0:
private def foo; end # similar for `protected`, `public`, `module_function`
# Before Ruby 2.0:
def map; end
alias_method :collect, :map
# After Ruby 2.0:
alias_method :collect, def map; end
On a personal note, I would have preferred a method definition expression to evaluate to an UnboundMethod object corresponding to that method, and methods like public, private, protected, alias_method, module_function etc. should be amended to accept UnboundMethods in addition to Symbols and Strings.
The person who proposed this had in mind a usage like this:
private def foo
...
end
protected def bar
...
end
Methods such as public, private, protected take symbols as arguments. The point was to make use of this syntax.
All method defs return symbols in Ruby >=2.1 (not just the ones in IRB).
For example:
class Foo
p def bar; end
end
# => prints :bar
Why is this interesting?
You may have noticed that there are many methods, particularly class-level methods, that take the symbolized name of another method as an argument. You may be familiar with before_filter in Rails controllers. Since method defs return symbols, you could potentially do this:
class MyController < ApplicationController
before_filter def my_filter
# do stuff
end
end
IRB respects the ruby standard “the result of last executed statement is returned from method.” Imagine the code:
def a
def b
# do stuff
end
end
What is the result of execution this code? It follows:
a
# => :b
a.class
# => Symbol < Object
That said, IRB executes the method definition and returns/prints out it’s result. Which is, apparently, a Symbol instance.
Just want to enquire what the right practice is.
My preference is to use procs, simply because I think that defining methods inside of methhods is a bit untidy and should be done only when necessary. To get around it, I simply use procs.
What is the right / better way to do it and why? (apart from the proc's ability to access the main method's variables defined before itself)
def meth( params_prime )
calculations = do_something_with_whatever
def sub_meth( params_sub )
do_something_with_params_sub
end
sub_meth_params(calculations) # is this better?
proc1 = proc{ |params_sub| do_something_with_params_sub }
proc1.call(calculations) # or is this?
end
It is not clear what your specific use-case is, but I would definitely go for procs or lambdas. There is less overhead when defining a proc or lambda dynamically, they are passable, so if needed you could return them and they could be used outside the function.
Using "def" exposes the method as an instance method outside of the current method scope (so in the containing class, which could be Object in your case). This may or may not be with you want. If you want to use an anonymous function only available in the local scope, use a lambda.
Also Proc vs Lambda: I generally prefer to use lambdas since they behave a little more "predictable", meaning: as you would expect (check passed variables, and return just returns from the lambda, proc returns from the called scope). But from your example it is hard to deduce what would apply. I think the key-difference is: lambas are ment to be passed around, and thus behave a little more sanely. If this is not your use-case, use Proc :) (a write-up of the difference).
If you want to use sub_func to encapsulate it from call from other methods you can use a class to group function and sub_func together and make sub_func private. Otherwise if you want to pass this function as a parameter further you can declare it as lamda.
def func params_prime
sub_func = ->(params_sub){do_something_with_params}
sub_func.call(params_prime)
end
Defining methods inside methods is a feature of Ruby that may have its use. But something is telling me that you are asking a very advanced question while you are still a beginner level Rubyist. Do you know what default definee is? If not, check this article by Yugui.
Procs are very important in Ruby, but newbies tend to use them instead of defining methods in appropriate objects, which is the exact smell I'm getting from your question. The normal way of doing things in OO languages of Ruby family is to define methods on objects:
class Foo
def bar *params
# do something with params
end
end
Since you do not understand the meaning of defining methods inside methods, refrain from doing it for the next 6 months. Once you understand objects, you can start experimenting with this very advanced feature again.
APPENDIX:
Since you demonstrated intrest, let me show you that using def in def at the top level is a frownable-upon thing to do. Normally, when you define a method on some class without further adornment, it becomes a public instance method of that class:
class X
def foo; "foo" end
end
X.instance_methods.include? :foo
#=> true
When you use def in a def, the definee for the inner def is going to be X:
class X
def bar
def baz
"baz"
end
"bar"
end
end
When you execute the above code, instance method #bar becomes defined on X:
X.instance_methods.include? :bar
#=> true
But #baz not yet:
X.instance_methods.include? :baz
#=> false
Only after you call #bar at least once does the method become defined on X:
X.new.bar
#=> "bar"
X.instance_methods.include? :baz
#=> true
And now I would like to ask you to appreciate how terrible thing just happened: An instance just modified its mother class. That's a violation. A violation of such a basic principle of OO design, that I'm not even sure it has a name. This technique is great for obfuscated coding competitions, but in production, it's taboo. Ruby gives you the freedom to break that taboo, gives you the rope to hang yourself on, but you don't do it under any kind of normal circumstances.
So what can be worse than a def inside a def in a class definition? The answer is, a def inside a def at the top level. Let me show you why. Normally, when you define methods with def at the top level, the default definee is Object, but the top level defnitions become private instance methods of object. This is to prevent the unintended consequence of top level defs, because almost all Ruby objects inherit from Object. For example, if you define:
class Object
def foo; "foo" end
end
Now all your objects will respond to foo:
foo #=> "foo"
1.foo #=> "foo"
[].foo #=> "foo
When we define methods at the top level, we usually just intend to use the method at the top level, and don't want every single object to inherit it. For that reason, top level defs become private:
hello #=> NameError: undefined local variable or method `hello' for main:Object
1.hello #=> NoMethodError: undifined method 'hello' for 1:Fixnum
Now we use def at the top level:
def hello; "hello" end
We can see that method #hello is has not become an instance methods of Object:
Object.instance_methods.include? :hello
#=> false
Mysteriously, it became its private method:
Object.private_instance_methods.include? :hello
#=> true
This way, we avoid the unintended consequence of defining #hello method for every single object. But the inheritance is there. The error message has changed:
1.hello #=> NoMethodError: private method 'hello' called for 1:Fixnum
And we can forcibly call the method via #send:
1.send :hello
#=> "hello"
Mysteriously, at the top level, we are allowed to call this private method without #send:
hello
#=> "hello"
And now, what happens when you do def in def at the top level:
def bar
def baz; "baz" end
"bar"
end
You define a private instance method Object#bar in an expected way. But when you call it, alas, the top level magic no longer works and a public method Object#baz gets defined:
bar #=> "bar"
This way, not just the top level, but every single Ruby object got polluted with your #baz method:
1.baz #=> "baz"
Class.baz #=> "baz"
This is why I told you to refrain from using this idiom until you progress from the level of unconscious incompetence to the level of conscious incompetence. I recommend you to read more about top level methods in Ruby.
In a unit test I need to test whether alias methods defined by alias_method have been properly defined. I could simply use the same tests on the aliases used for their originals, but I'm wondering whether there's a more definitive or efficient solution. For instance, is there a way to 1) dereference a method alias and return its original's name, 2) get and compare some kind of underlying method identifier or address, or 3) get and compare method definitions? For example:
class MyClass
def foo
# do something
end
alias_method :bar, :foo
end
describe MyClass do
it "method bar should be an alias for method foo" do
m = MyClass.new
# ??? identity(m.bar).should == identity(m.foo) ???
end
end
Suggestions?
According to the documentation for Method,
Two method objects are equal if that
are bound to the same object and
contain the same body.
Calling Object#method and comparing the Method objects that it returns will verify that the methods are equivalent:
m.method(:bar) == m.method(:foo)
bk1e's method works most of the time, but I just happened to hit the case where it doesn't work:
class Stream
class << self
alias_method :open, :new
end
end
open = Stream.method(:open)
new = Stream.method(:new)
p open, new # => #<Method: Stream.new>, #<Method: Class#new>
p open.receiver, new.receiver # => Stream, Stream
p open == new # => false
The output is produced in Ruby 1.9, not sure if it's a bug or not since Ruby 1.8 produces true for the last line. So, if you are using 1.9, be careful if you are aliasing an inherited class method (like Class#new), These two methods are bound to the same object (the class object Stream), but they are considered not equivalent by Ruby 1.9.
My workaround is simple - alias the original method again and test the equality of the two aliases:
class << Stream; alias_method :alias_test_open, :new; end
open = Stream.method(:open)
alias_test_open = Stream.method(:alias_test_open)
p open, alias_test_open # => #<Method: Stream.new>, #<Method: Stream.new>
p open.receiver, alias_test_open.receiver # => Stream, Stream
p open == alias_test_open # => true
Hope this helps.
UPDATE:
See http://bugs.ruby-lang.org/issues/7613
So Method#== should return false in this case since a super call would invoke different methods; it is not a bug.
Calling MyClass.instance_method(:foo) will result UnboundMethod instance, which has eql? method.
So the answer is:
describe MyClass do
subject { described_class }
specify do
expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar))
end
end