Forum: Ruby Calling a Function Before It's Defined

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Mark B. (Guest)
on 2009-04-09 21:44
I would like to be able to call a function (or a class,
when I get more object-oriented) earlier in the program
file than where I define it.  Such a "top-down" layout
seems natural to me.  In C I could use a function
prototype for this.  If I try it in Ruby, I get an error
(see code below).

Even if I do define everything before I use it, how could
I write a recursive function, or two mutually recursive
functions?

s = "abc"

# gives error: undefined method `f' for main:Object (NoMethodError)
f(s)

def f(x)
  print('f: ', x, "\n")
end

# works OK
f(s)
Joel VanderWerf (Guest)
on 2009-04-09 21:55
(Received via mailing list)
Mark B. wrote:
> I would like to be able to call a function (or a class,
> when I get more object-oriented) earlier in the program
> file than where I define it.  Such a "top-down" layout
> seems natural to me.  In C I could use a function
> prototype for this.  If I try it in Ruby, I get an error
> (see code below).

Two ways:

foo
BEGIN {
   def foo; end
}

or

END {
   foo
}
def foo; end

> Even if I do define everything before I use it, how could
> I write a recursive function, or two mutually recursive
> functions?

Define the two functions before you call either one. No prob.

def foo(n); p n; bar(n-1); end
def bar(n); foo(n) if n>0; end

p bar(3)
matt neuburg (Guest)
on 2009-04-09 22:45
(Received via mailing list)
Mark B. <removed_email_address@domain.invalid> wrote:

> f(s)
>
> def f(x)
>   print('f: ', x, "\n")
> end
>
> # works OK
> f(s)

The fact that everything is executable code, including "module M",
"class C", and "def", and that code is executed in the order in which it
is encountered, is part of what makes Ruby R.. It is used to
accomplish many cool things, like modifying modules that already exist.
So don't worry, be happy. m.
Mark B. (Guest)
on 2009-04-09 23:02
Joel VanderWerf wrote:
> foo
> BEGIN {
>    def foo; end
> }

Thanks! Just to make it clear for other beginners
like me, here's the fixed version of my code:
-------------------
s = "abc"
f(s)

BEGIN {
def f(x)
    print('f: ', x, "\n")
end
}
-------------------
Quoting _Programming Ruby_ (the Pickaxe book):

BEGIN and END Blocks
Every Ruby source file can declare blocks of code to be run
as the file is being loaded (the BEGIN blocks) and after
the program has finished executing (the END blocks).

  BEGIN {
  begin code
  }

  END {
  end code
  }

A program may include multiple BEGIN and END blocks. BEGIN
blocks are executed in the order they are encountered.
END blocks are executed in reverse order.
Sebastian H. (Guest)
on 2009-04-10 00:26
(Received via mailing list)
Mark B. wrote:
> I would like to be able to call a function (or a class,
> when I get more object-oriented) earlier in the program
> file than where I define it.  Such a "top-down" layout
> seems natural to me.  In C I could use a function
> prototype for this.

The reason why you have to declare a function in C before you call it
(before
meaning the code position) is fundementally different from why you have
to
define it in ruby before you call it (here before means the runtime).

Examples:
def foo()
  bar
end
def bar()
end
foo
Works just fine (because the code in foo that references bar executes
after
bar has been defined (even if it's position in the code is earlier).

def foo()
  1
end
def bar()
  foo
end
bar #=> 1
def foo()
  2
end
bar #=> 2
You can redefine methods and ruby always executes the version of the
method
that's currently in existence.

def foo()
  def bar()
  end
end
bar #error
foo
bar # Now it works

You can define method a within method b. That will have the effect that
after
running method b, method a will be defined (although it wasn't before).
You can also redefine methods that way:
def foo() 1 end
def bar() def foo() 2 end end
foo #=> 1
bar
foo #=> 2

All this has the effect that you can't forward declare methods like you
can in
C. If you do this:
def foo() end
foo
def foo() bar end
The call in line 2 will call the empty version of foo because that is
the
version currently in existence.

HTH,
Sebastian
Mark B. (Guest)
on 2009-04-10 22:17
Mark B. wrote:
> here's the fixed version of my code:
> -------------------
> s = "abc"
> f(s)
>
> BEGIN {
> def f(x)
>     print('f: ', x, "\n")
> end
> }
> -------------------
A friend thought of another way,
that avoids even the BEGIN hack:

def mainn
    s = "abc"
    f(s)
end

def f(x)
    print('f: ', x, "\n")
end

mainn
-------------------
This topic is locked and can not be replied to.