Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 Work In Progress - Eiffel Whirlwind
Index -> General Programming
View previous topic Printable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
wtd




PostPosted: Sat Jul 14, 2007 3:53 pm   Post subject: Work In Progress - Eiffel Whirlwind

Theory Warning!

Eiffel is a purely object-oriented, statically-typed, manifestly-typed programming language.

As it is purely object-oriented, everything is an object. Everything exists within a class.

All things within classes are "features" and are either variables, constants, or routines. Routines are either functions, which return a new object and make no changes to the class, or procedures which return nothing, and do have side-effects on the class.

And that's enough theory for now.

The Simplest Possible Class

code:
class
   HELLO_WORLD
end


Class names are always all-caps, and have words separated by underscores.

Let's Add a Feature

code:
class
   HELLO_WORLD
feature
   Message : STRING is "Hello, world!"
end


Here our feature is a constant string. Because it's a constant, it's capitalized.

Let's Add Another

code:
class
   HELLO_WORLD
feature
   Message : STRING is "Hello, world!"
   Surly_message : STRING is "Hey stupid world..."
end


Let's Add a Routine

code:
class
   HELLO_WORLD
feature
   Message : STRING is "Hello, world!"
   Surly_message : STRING is "Hey stupid world..."
   
   say_hello is
      do
         io.put_line(Message)
      end
end


A Variable

code:
class
   HELLO_WORLD
feature
   Message : STRING is "Hello, world!"
   Surly_message : STRING is "Hey stupid world..."
   
   name : STRING
   
   say_hello is
      do
         io.put_line(Message)
      end
end


Initializing That Variable

We need a creation routine. They're just like regular routines. Except that in their case they also get a mention in the create clause. The "make" routine is the most commonly used name.

code:
class
   HELLO_WORLD
create
   make
feature
   name : STRING
   
   make(initial_name : STRING) is
      do
         name := initial_name
      end
   
   say_hello is
      do
         io.put_line("Hello, " + name + "!")
      end
end


This is Just a Class

We have yet to create a program. A program needs an entry point.

And entry point in an Eiffel program is just a creation routine. By default the compiler will choose the "make" routine, but we can tell it to use any creation routine as the entry point. That will be useful, since "make" in the above does very little in terms of output.

code:
class
   HELLO_WORLD
create
   make, entry_point
feature
   name : STRING
   
   make(initial_name : STRING) is
      do
         name := initial_name
      end
     
   entry_point is
      do
         say_hello
      end
   
   say_hello is
      do
         io.put_line("Hello, " + name + "!")
      end
end


There's a problem, though.

When entry_point is executed, nothing has actually been assigned to "name" meaning that it remains Void.

code:
class
   HELLO_WORLD
create
   make, entry_point
feature
   name : STRING
   
   make(initial_name : STRING) is
      do
         name := initial_name
      end
     
   entry_point is
      do
         make("Foo")
     
         say_hello
      end
   
   say_hello is
      do
         io.put_line("Hello, " + name + "!")
      end
end


Now, we can compile with:

code:
$ se c -clean hello_world entry_point


And run it with:

code:
$ ./hello_world


Which results in:

code:
Hello, Foo!


The "-clean" option removes all of the intermediate files the SmartEiffel compiler creates as it compiles the code to C, and then uses a C compiler to generate the final executable.

Another Class

code:
class
   NAME
create
   make
feature
   first_name, last_name : STRING
   
   make(f, l : STRING) is
      do
         first_name := f
         last_name := l
      end
     
   full_name : STRING is
      do
         Result := first_name + " " + last_name
      end
     
end


Using It

code:
class
   HELLO_WORLD
create
   make
feature
   name : NAME
   
   make is
      do
         create name.make("Foo", "Bar")
         
         say_hello
      end
   
   say_hello is
      do
         io.put_line("Hello, " + name.full_name + "!")
      end
end


Compile with:

code:
$ se c -clean hello_world


Inhertitance and Some Polymorphism

code:
class
   NAME
create
   make
feature
   first_name, last_name : STRING
   
   make(f, l : STRING) is
      do
         first_name := f
         last_name := l
      end
     
   full_name : STRING is
      do
         Result := first_name + " " + last_name
      end
     
end


code:
class
   FORMAL_NAME
inherit
   NAME
      redefine full_name end
create
   make_with_title
feature
   title : STRING
   
   make_with_title(t, f, l : STRING) is
      do
         make(f, l)
         
         title := t
      end
     
   full_name : STRING is   
      do
         Result := title + " " + Precursor
      end
end


code:
class
   HELLO_WORLD
create
   make
feature
   name : NAME
   
   make is
      do
         create { FORMAL_NAME } name.make_with_title("Foo", "Bar")
         
         say_hello
      end
   
   say_hello is
      do
         io.put_line("Hello, " + name.full_name + "!")
      end
end


Deferred Features

code:
class
   GREETABLE
feature
   greetable_name : STRING is
      deferred
      end
     
   greeting : STRING is
      do
         Result := "Hello, " + greetable_name + "!"
      end
     
   greet is
      do
         greet_on(io)
      end
     
   greet_on(output : OUTPUT_STREAM) is
      do
         output.put_line(greeting)
      end
end


And now to rewrite our previous code to take advantage of this.

code:
class
   NAME
inherit
   GREETABLE
create
   make
feature
   first_name, last_name : STRING
   
   make(f, l : STRING) is
      do
         first_name := f
         last_name := l
      end
     
   greetable_name, full_name : STRING is
      do
         Result := first_name + " " + last_name
      end
end


code:
class
   FORMAL_NAME
inherit
   NAME
      redefine greetable_name, full_name end
create
   make_with_title
feature
   title : STRING
   
   make_with_title(t, f, l : STRING) is
      do
         make(f, l)
         
         title := t
      end
     
   greetable_name, full_name : STRING is   
      do
         Result := title + " " + Precursor
      end
end


code:
class
   HELLO_WORLD
create
   make
feature   
   make is
      local
         name : NAME
      do
         create { FORMAL_NAME } name.make_with_title("Mr.", "Foo", "Bar")
         
         name.greet
      end
end


Building Made Easier

Instead of typing out the SmartEiffel compiler command each time, let's use an ACE file named "hello_world.ace".

code:
system
   "hello_world"
root
   HELLO_WORLD(hello_world_cluster):make
default
   collect(yes);
cluster
   standard: "${path_lib}/loadpath.se"
   hello_world_cluster: "."
generate
   clean(yes);
end


First we define the name of the system being created.

Then we specify the root class and the creation routine to use as the entry point.

Then we set a series of defaults. Here the only one I've bothered with is turning garbage collection on.

Next we define clusters. Clusters allow us to group classes, and tell the compiler where to look for classes. The "standard" cluster simply points to the standard library, with the help of an environment variable.

The hello_world_cluster points to the current directory.

Within the generate clause I can set a series of options for the generated C code. I tell it to clean up after the build.

I can run this with:

code:
$ se c hello_world.ace
$ ./hello_world
Hello, Mr. Foo Bar!
$


Making Choices

code:
class
   NAME
inherit
   GREETABLE
      redefine greeting end
create
   make
feature
   first_name, last_name : STRING
   
   make(f, l : STRING) is
      do
         first_name := f
         last_name := l
      end
     
   greeting : STRING is
      do
         if first_name = last_name then
            Result := "What a stupid name..."
         else
            Result := Precursor
         end
      end
     
   greetable_name, full_name : STRING is
      do
         Result := first_name + " " + last_name
      end
end


Iterating

code:
class
   HELLO_WORLD
create
   make
feature   
   make is
      local
         name : NAME
         iter : ITERATOR[CHARACTER]
      do
         create { FORMAL_NAME } name.make_with_title("Mr.", "Foo", "Bar")
         
         from
            iter := name.first_name.get_new_iterator
         until
            iter.is_off
         loop
            put_char_on_line(iter.current)
           
            iter.next
         end
      end
     
   print_char_on_line(ch : CHARACTER) is
      do
         io.put_character
         io.put_new_line
      end
end


Streamlining with Agents

code:
class
   HELLO_WORLD
create
   make
feature   
   make is
      local
         name : NAME
      do
         create { FORMAL_NAME } name.make_with_title("Mr.", "Foo", "Foo")
         
         name.greet
         
         name.first_name.do_all(agent io.put_character(?))
      end
end




Polymorphism Bites Back

So with NAME and FORMAL_NAME we saw some polymorphism. Even if we specified that a variable was a NAME, and assigned a FORMAL_NAME to it (via creation or otherwise), the FORMAL_NAME version of full_name would be used.

This is really really good. But...

What about the title feature? NAME has no such thing. As such, anything we have guaranteed only to be a name cannot be guaranteed to have a title feature.

code:
class
   HELLO_WORLD
create
   make
feature   
   make is
      local
         name : NAME
         another_name : FORMAL_NAME
      do
         create { FORMAL_NAME } name.make_with_title("Mr.", "Foo", "Foo")
         
         name.greet
         
         another_name ?= name
         
         io.put_line(another_name.title)
      end
end


The ?= operator serves the same purpose as :=, but evaluates whether or not it will succeed at run-time, rather than compile-time.
Sponsor
Sponsor
Sponsor
sponsor
Clayton




PostPosted: Sat Jul 14, 2007 7:31 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

Awesome stuff wtd! Definitely something I have to check out. Quick query, does indentation have anything to do with how code is seperated (like Python par example)?
wtd




PostPosted: Sat Jul 14, 2007 7:33 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

Nope. Just makes it look nice.
Clayton




PostPosted: Sat Jul 14, 2007 7:34 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

so under the create clause nothing to do with indentation then? Just as long as you have a comma in between each word I'm guessing?
wtd




PostPosted: Sat Jul 14, 2007 11:51 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

Yes.
rdrake




PostPosted: Tue Jul 17, 2007 2:34 am   Post subject: Re: Work In Progress - Eiffel Whirlwind

For the benefit of those interested, the following sample was created by myself with (massive) help from wtd. It shows some overriding of methods, hiding of methods, and probably some other stuff too. Enjoy!

code:
class
  VECTOR3D
inherit
  ANY
    redefine out, print_on, is_equal end
create
  make, entry_point
feature
  x, y, z : REAL
 
  make (x_init, y_init, z_init : REAL) is
    do
      x := x_init
      y := y_init
      z := z_init
    end
   
  entry_point is
    local
      v, v1 : VECTOR3D
    do
      create v.make(1, 2, 3)
      create v1.make(3, 2, 1)
      v.magnitude.print_on(io)
      v.normalize(v1).print_on(io)
      v.cross_product(v1).print_on(io)
      v.is_equal(v1).print_on(io)
    end
   
  normalize (vector : VECTOR3D) : VECTOR3D is
    do
      create Result.make(vector.x / magnitude, vector.y / magnitude, vector.z / magnitude)
    end
   
  dot_product (vector : VECTOR3D) : REAL is
    do
      Result := x * vector.x + y * vector.y + z * vector.z
    end
   
  cross_product (vector : VECTOR3D) : VECTOR3D is
    do
      create Result.make(vector.y * z - vector.z * y, vector.z * x - vector.x * z, vector.x * y - vector.y * x)
    end
 
  out : STRING is
    do
      Result := "(" + x.to_string + ", " + y.to_string + ", " + z.to_string + ")"
    end
 
  print_on (output : OUTPUT_STREAM) is
    do
      output.put_line(out)
    end
   
  is_equal(other : VECTOR3D) : BOOLEAN is
    do
      Result := x.is_equal(other.x) and then y.is_equal(other.y) and then z.is_equal(other.z)
    end
feature {VECTOR3D}
  magnitude : REAL is
    do
      Result := (x ^ 2 + y ^ 2 + z ^ 2).sqrt
    end
end


Naturally you compile it with this:
code:
se c -clean vector3d.e entry_point
wtd




PostPosted: Tue Jul 17, 2007 2:37 am   Post subject: RE:Work In Progress - Eiffel Whirlwind

Excellent!
Aziz




PostPosted: Tue Jul 17, 2007 8:24 am   Post subject: RE:Work In Progress - Eiffel Whirlwind

It seems very verbose to me, though interesting. What did you mean by manifestly-typed, wtd?
Sponsor
Sponsor
Sponsor
sponsor
wtd




PostPosted: Tue Jul 17, 2007 1:54 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

Types have to be explicitly declared, as in Java, C++, etc. This is as opposed to something like O'Caml.

As for verbosity, Bertrand Meyer's perspective, I believe, was that one would have verbose design documents to explain away terse code, so he felt it better to just have code that was as self-documenting as possible.
Aziz




PostPosted: Tue Jul 17, 2007 2:10 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

Is inherit ANY the likes of deriving from a base object class?

Also, could you expand on the 'create' routines, etc?

EDIT: What would you do if you had a long line? I take it line breaks are the statement separators.
wtd




PostPosted: Tue Jul 17, 2007 5:34 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

Yes, ANY is the root of the inheritance hierarchy. You automatically inherit from ANY, but sometimes it needs to be explicit so that you can redefine, rename or undefine features from ANY.

Create routines are routines which may be used when an object is created in order to give it an initial state. Create routines may be used elsewhere in the program as well.

You need do nothing to continue long lines.

code:
Result := a + b + c


code:
Result := a +
          b +
          c
Aziz




PostPosted: Tue Jul 17, 2007 5:38 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

What about polymorphism? Do virtual methods need to be defined explicitly, such as in C#, or or they more like Java? And how would this be handled when you undefine a feature?
wtd




PostPosted: Tue Jul 17, 2007 5:42 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

code:
class
   FOO
feature
   baz : STRING is
      do
         Result := "Foo"
      end
end


code:
class
   BAR
inherit
   FOO
      redefine baz end
feature
   baz : STRING is
      do
         Result := "Bar"
      end
end


code:
class
   TEST
create
   make
feature
   make is
      local
         f : FOO
      do
         create { BAR } f

         io.put_line(f.baz)
      end
end
Aziz




PostPosted: Tue Jul 17, 2007 6:05 pm   Post subject: RE:Work In Progress - Eiffel Whirlwind

Running test would output "Bar".
Display posts from previous:   
   Index -> General Programming
View previous topic Tell A FriendPrintable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 14 Posts ]
Jump to:   


Style:  
Search: