module_function :func vs. MyModule.func?

7

7stud --

The following produce the same output:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

MyModule.greet

#-----vs.-----------

module MyModule
def MyModule.greet
puts "hello"
end
end

MyModule.greet


What is module_function used for?
 
7

7stud --

7stud said:
The following produce the same output:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

MyModule.greet

#-----vs.-----------

module MyModule
def MyModule.greet
puts "hello"
end
end

MyModule.greet


What is module_function used for?


Ahhh, is this it:


module MyModule
def greet
puts "hello"
end
end

module OtherModule
include MyModule

module_function :greet
end

OtherModule.greet
 
7

7stud --

7stud said:
module MyModule
def greet
puts "hello"
end
end

module OtherModule
include MyModule

module_function :greet
end

OtherModule.greet


On p. 355 of "Programming Ruby (2nd ed)", there is the equivalent of
this example:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

MyModule.greet

As far as I can tell, in that example the module_function has no purpose
since I could just as easily make this change:

module MyModule
def MyModule.greet
puts "hello"
end
end

MyModule.greet

Is there any reason to use module_function in that example?
 
J

James Hunt

On p. 355 of "Programming Ruby (2nd ed)", there is the equivalent of
this example:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

MyModule.greet

As far as I can tell, in that example the module_function has no purpose
since I could just as easily make this change:

module MyModule
def MyModule.greet
puts "hello"
end
end

MyModule.greet

Is there any reason to use module_function in that example?

I believe the primary different shows up when the module is included
in another class. Consider this little snippet:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

class MyClass
include MyModule

def hello
greet
end
end

MyModule.greet
MyClass.new.hello

When this gets run, the output will be:
hello
hello

The kicker is that greet is mixed into MyClass as a private method
(try calling MyClass.new.greet and watch the access error).

Using your explicit definition as such:

module MyExplicitModule
def MyExplicitModule.greet
puts "hello, explicitly!"
end
end

class MyExplicitClass
include MyExplicitModule

def hello
greet
end
end

MyExplicitModule.greet
MyExplicitClass.new.greet

The output of this code when run is
hello
module_function.rb:31:in `hello': undefined local variable or method
`greet' for #<MyExplicitClass:0xb7cc7eac> (NameError)
from module_function.rb:36

Essentially, by defining explicitly as MyExplicitModule.greet, the
method becomes a member of the module's singleton class, and does not
get mixed into classes that include it. The module_function call
makes the method passed private and creates a singleton method.

You may also want to check out:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/17670

The poster gives a good example of the usage (Math.sqrt)

HTH
 
7

7stud --

James said:
I believe the primary different shows up when the module is included
in another class.

Using your explicit definition as such:

module MyExplicitModule
def MyExplicitModule.greet
puts "hello, explicitly!"
end
end

class MyExplicitClass
include MyExplicitModule

def hello
greet
end
end

MyExplicitModule.greet
MyExplicitClass.new.greet

The output of this code when run is
hello
module_function.rb:31:in `hello': undefined local variable or method
`greet' for #<MyExplicitClass:0xb7cc7eac> (NameError)
from module_function.rb:36

Using your last example with module_function, I get the same result:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

class MyClass
include MyModule
end

MyModule.greet
MyClass.new.greet


--output:--
hello
r1test.rb:13: private method `greet' called for #<MyClass:0x25490>
(NoMethodError)

So, I'm not seeing any difference.
 
J

James Hunt

Using your last example with module_function, I get the same result:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

class MyClass
include MyModule
end

MyModule.greet
MyClass.new.greet


--output:--
hello
r1test.rb:13: private method `greet' called for #<MyClass:0x25490>
(NoMethodError)

So, I'm not seeing any difference.

If you look at my code, the MyClass definition creates an instance
method called hello that calls the private greet method. In the
Explicit example, greet just doesn't exist in MyExplicitClass after
the mixin...
 
T

Trans

The following produce the same output:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

MyModule.greet

#-----vs.-----------

module MyModule
def MyModule.greet
puts "hello"
end
end

MyModule.greet

What is module_function used for?


Allow me to further confuse you:

module MyModule
extend self

def greet
puts "hello"
end
end

MyModule.greet

Now I will explain. I the 1st case, using module_function makes an
actual copy of the instance method and defines it as a singleton
method of the module. In the 2nd case, you never have the instance
method to begin with, you simply defined the singleton method
directly. So to illustrate, the 1st example is equivalent to this:

module MyModule
def greet
puts "hello"
end

def MyModule.greet
puts "hello"
end
end

Now for my last example. In which case, we defined the instance
method, but have also included the module into it's own singleton
space. It is functionally the same as the 1st case but is also dynamic
--if we were to add a new method to MyModule later it would
automatically appear as a module method as well.

HTH,
T.
 
7

7stud --

James said:
If you look at my code, the MyClass definition creates an instance
method called hello that calls the private greet method. In the
Explicit example, greet just doesn't exist in MyExplicitClass after
the mixin...

As far as I can tell, your private hello method is irrelevant since you
never call the hello method:
MyExplicitModule.greet
MyExplicitClass.new.greet

If I add the hello method to my last example that uses module_function,
I get the same output:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

class MyClass
include MyModule

def hello
greet
end
end

MyModule.greet
MyClass.new.greet

--output:--
hello
r1test.rb:18: private method `greet' called for #<MyClass:0x25350>
(NoMethodError)
 
7

7stud --

Trans said:
Allow me to further confuse you:

Thanks for the response. Unfortunately, you're speaking a language I
can't understand yet. All I can do at this point is look at the output
and try to discern a difference.
 
L

Logan Capaldo

What is module_function used for?
--

module_function is used to help give us namespaces. The most visible
example is the Math module. Every method in there is
module_function'ed.

2 * Math.sin( 3.4 ) + Math.exp(24) # boy it sure is tiring typing
Math. all the time
include Math
2 * sin(3.4) + exp(24) # much better
 
7

7stud --

Logan said:
module_function is used to help give us namespaces. The most visible
example is the Math module. Every method in there is
module_function'ed.

2 * Math.sin( 3.4 ) + Math.exp(24) # boy it sure is tiring typing
Math. all the time
include Math
2 * sin(3.4) + exp(24) # much better

Ah hah! A difference I can discern:

module MyModule
def MyModule.greet
puts "hello"
end
end

MyModule.greet
#boy it sure is tiring typing MyModule every time I want to say hello

include MyModule
greet

--output:--
hello
r1test.rb:10: undefined local variable or method `greet' for main:Object
(NameError)
 
J

James Hunt

As far as I can tell, your private hello method is irrelevant since you
never call the hello method:
If you look back at the original code posting, there were two test
sets: The first one (with MyModule) called MyClass.new.hello, whereas
the second one (with MyExplicitModule) called MyClass.new.greet.
Perhaps a bit confusing on my part - I apologize.

MyClass#hello was a public method calling MyClass#greet (a private
method) that was mixed in via the include of MyModule.
Again, this is the second test set, not the first. My apologies for
the confusion.
If I add the hello method to my last example that uses module_function,
I get the same output:

module MyModule
def greet
puts "hello"
end

module_function :greet
end

class MyClass
include MyModule

def hello
greet
end
end

MyModule.greet
MyClass.new.greet

--output:--
hello
r1test.rb:18: private method `greet' called for #<MyClass:0x25350>
(NoMethodError)

Because the last two lines should be:
MyModule.greet
MyClass.new.hello

That being said, I think Logan offered a much better explanation. +1 Logan
 
7

7stud --

Thanks for all the help. Here is a summary of the problem and solution:

module Test
def Test.show
puts "testing"
end

def f
puts "goodbye"
end
end

Test.show #testing
Test.f #error

include Test

f #goodbye
show #error

As the example above shows, there is no way to achieve both of the
following:

1) When the Test module isn't included in order to avoid potential name
clashes of Test's methods with other methods having the same name, being
able to call all the methods using the syntax: Test.name.

2) When the Test module is included in order to avoid having to to type
the module name in front of the method names and name clashes aren't a
concern, being able to call all the methods using the syntax: name.

module_function allows you to achieve both 1 and 2:

module Test
def show
puts "testing"
end
def f
puts "goodbye"
end

module_function :show, :f
end

Test.show #testing
Test.f #goodbye

include Test

show #testing
f #goodbye
 
7

7stud --

do not forget third use of module_function since it's one of the nifty
features..

3) being able to change the module methods (or module "functions" so to
speak) independently of the original methods. Remember, module functions
are copies of the original,

ergo you can just modify the copies...


A new twist! I'll quote your original example:

(I guess I won't--it's too long)


How does that work? You add a new instance method with the same name
as an existing instance method to the module, and somehow the new
instance method
overwrites the old one, and the old instance method gets promoted to a
"class" method?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top