Saturday, September 25, 2010

Nemerle - Basics by Example



Continue with the Basics by Example; today's version of the post written in Nemerle Enjoy!

You can copy and paste the code below in your favorite IDE/Editor and start playing and learning with it. This little "working" program will teach you the basics of the Programming Language.

There are some "comments" on the code added just to tell you what are or how are some features called. In case you want to review the theory, you can read my previous post, where I give a definition of each of the concepts mentioned on the code. You can find it here: http://carlosqt.blogspot.com/2010/08/new-series-languages-basics-by-example.html 


Greetings Program - Verbose
// Nemerle Basics
using System;
namespace NGreetProgram
{
    // Greeting Class
    internal class Greet 
    {
        // Fields or Attributes
        private mutable message : string;
        private mutable name : string;
        private mutable loopMessage : int;
        // Properties
        public Message : string 
        {
            get { this.message; }
            set { this.message = this.Capitalize(value); }
        }
        public Name : string {
            get { this.name; }
            set { this.name = this.Capitalize(value); }
        }
        public LoopMessage : int {
            get { this.loopMessage; }
            set { this.loopMessage = value; }
        }
        // Constructor
        public this() {
            this.message = "";
            this.name = "";
            this.loopMessage = 0;
        }
        // Overloaded Constructor
        public this(message : string, name : string, loopMessage : int) 
        {
            this.message = message;
            this.name = name;
            this.loopMessage = loopMessage;
        }
        // Method 1
        private Capitalize(val : string): string 
        {
            if (val.Length >= 1) {
                val[0].ToString().ToUpper() + val.Substring(1, val.Length - 1);
            }
            else {
                "";
            }
        }
        // Method 2
        public Salute() : void
        {
            // "for" statement
            for (mutable i : int = 0; i < this.loopMessage; i++) {
                Console.WriteLine("{0} {1}!", this.message, this.name);                
            }
        }
        // Overloaded Method 2.1
        public Salute(message : string, name : string, loopMessage : int) : void 
        {
            // "while" statement
            mutable i : int = 0;
            while(i < loopMessage) {
                Console.WriteLine("{0} {1}!", this.Capitalize(message), 
                                    this.Capitalize(name));                
                i++;
            }
        }
        // Overloaded Method 2.2
        public Salute(name : string) : void
        {
            // "switch/case" statement is not supported
            // using match statement instead
            def dtNow : DateTime = DateTime.Now;            
            match (dtNow.Hour) {
                |6|7|8|9|10|11 => this.message = "good morning,";
                |12|13|14|15|16|17 => this.message = "good afternoon,";
                |18|19|20|21|22 => this.message = "good evening,";
                |23|0|1|2|3|4|5 => this.message = "good night,";
                | _ => this.message = "huh?"
            }            
            Console.WriteLine("{0} {1}!", this.Capitalize(this.message), 
                                    this.Capitalize(name));
        }
    }

    // Console Program
    public module Program
    {
        public static Main() : void
        {
            // Define object of type Greet
            mutable g : Greet;            
            // Instantiate Greet. Call Constructor
            g = Greet();
            // Call Set Properties
            g.Message = "hello";
            g.Name = "world";
            g.LoopMessage = 5;
            // Call Method 2
            g.Salute();
            // Call Overloaded Method 2.1 and Get Properties
            g.Salute(g.Message, "nemerle", g.LoopMessage);
            // Call Overloaded Method 2.2
            g.Salute("carlos");
            
            // Stop and Exit
            Console.WriteLine("Press any key to exit...");
            _ = Console.Read();
        }
    }
}

Greetings Program - Minimal
// Nemerle Basics
using System;
// Greeting Class
class Greet 
{
    // Fields or Attributes
    mutable message : string;
    mutable name : string;
    mutable loopMessage : int;
    // Properties
    public Message : string 
    {
        get { message; }
        set { message = Capitalize(value); }
    }
    public Name : string {
        get { name; }
        set { name = Capitalize(value); }
    }
    public LoopMessage : int {
        get { loopMessage; }
        set { loopMessage = value; }
    }
    // Constructor
    public this() {
        message = "";
        name = "";
        loopMessage = 0;
    }
    // Overloaded Constructor
    public this(message : string, name : string, loopMessage : int) 
    {
        this.message = message;
        this.name = name;
        this.loopMessage = loopMessage;
    }
    // Method 1
    private Capitalize(val : string): string 
    {
        if (val.Length >= 1) {
            val[0].ToString().ToUpper() + val.Substring(1, val.Length - 1);
        }
        else {
            "";
        }
    }
    // Method 2
    public Salute() : void
    {
        // "for" statement
        for (mutable i = 0; i < loopMessage; i++) {
            Console.WriteLine("{0} {1}!", message, name);
        }
    }
    // Overloaded Method 2.1
    public Salute(message : string, name : string, loopMessage : int) : void 
    {
        // "while" statement
        mutable i = 0;
        while(i < loopMessage) {
            Console.WriteLine("{0} {1}!", Capitalize(message), 
                                Capitalize(name));
            i++;
        }
    }
    // Overloaded Method 2.2
    public Salute(name : string) : void
    {
        // "switch/case" statement is not supported
        // using match statement instead
        def dtNow = DateTime.Now;            
        match (dtNow.Hour) {
            |6|7|8|9|10|11 => message = "good morning,";
            |12|13|14|15|16|17 => message = "good afternoon,";
            |18|19|20|21|22 => message = "good evening,";
            |23|0|1|2|3|4|5 => message = "good night,";
            | _ => message = "huh?"
        }            
        Console.WriteLine("{0} {1}!", Capitalize(message), 
                                Capitalize(name));
    }
}

// Console Program
// Define object and Instantiate Greet. Call Constructor 
def g = Greet();
// Call Set Properties
g.Message = "hello";
g.Name = "world";
g.LoopMessage = 5;
// Call Method 2
g.Salute();
// Call Overloaded Method 2.1 and Get Properties
g.Salute(g.Message, "nemerle", g.LoopMessage);
// Call Overloaded Method 2.2
g.Salute("carlos");

// Stop and Exit
Console.WriteLine("Press any key to exit...");
_ = Console.Read();


And the Output is:


















Nemerle in Indentation Mode

Nemerle provides a very cool feature that allows you write your code in C-Like code blocks { } or Python-like indentation. You can do that using a compiler switch, or by adding a #pragma instruction to your code. Let's look at the Greetings Program (Minimal) and how it looks like after removing all those { and } characters from it, or should I say "Let's see how Pythonic it looks like?" hehe...

#pragma indent

using System;

class Greet

    mutable message : string;
    mutable name : string;
    mutable loopMessage : int;
    
    public Message : string
        get 
            message;
        set 
            message = Capitalize(value);
            
    public Name : string
        get
            name;
        set
            name = Capitalize(value);

    public LoopMessage : int
        get
            loopMessage;
        set
            loopMessage = value;
    
    public this()
        message = "";
        name = "";
        loopMessage = 0
    
    public this(message : string, name : string, loopMessage : int)
        this.message = message;
        this.name = name;
        this.loopMessage = loopMessage;
    
    private Capitalize(val : string): string     
        if (val.Length >= 1) 
            val[0].ToString().ToUpper() + val.Substring(1, val.Length - 1);        
        else 
            "";
    
    public Salute() : void
        for (mutable i = 0; i < loopMessage; i++) 
            Console.WriteLine("{0} {1}!", message, name);
    
    public Salute(message : string, name : string, loopMessage : int) : void     
        mutable i = 0;
        while(i < loopMessage) 
            Console.WriteLine("{0} {1}!", Capitalize(message), Capitalize(name));
            i++;
    
    public Salute(name : string) : void        
        def dtNow = DateTime.Now;            
        match (dtNow.Hour) 
            |6|7|8|9|10|11 => message = "good morning,";
            |12|13|14|15|16|17 => message = "good afternoon,";
            |18|19|20|21|22 => message = "good evening,";
            |23|0|1|2|3|4|5 => message = "good night,";
            | _ => message = "huh?"
                    
        Console.WriteLine("{0} {1}!", Capitalize(message), Capitalize(name));
         
mutable g = Greet()

g.Message = "hello";
g.Name = "world";
g.LoopMessage = 5;

g.Salute()
g.Salute(g.Message, "nemerle", g.LoopMessage);
g.Salute("carlos");

// Stop and Exit
Console.WriteLine("Press any key to exit...");
_ = Console.Read();


Wow, this last example looked too hybrid to me!
(C#-JScript-Boo-Python-F#) = Nemerle!


Auto-Implemented Properties in Nemerle

As with other .NET languages (C#,VB.NET,C++) Nemerle provides built in syntax to create auto-implemented properties. Auto-implemented properties enable you to quickly specify a property of a class without having to write code to Get and Set the property. The compiler will automatically create a private field to store the property variable in addition to creating the associated get and set procedures.

#pragma indent
using System;

/* In our class, we can void typing the Fields/Attributes 
and go directly to the properties */
class Greet
    //mutable message : string;
    //mutable name : string;
    //mutable loopMessage : int;
    
// using pragma indent
    public Message : string
        get; set;
    public Name : string
        get; set;
    public LoopMessage : int
        get; set;
// or not
    public Message : string {get; set;}
    public Name : string {get; set;}
    public LoopMessage : int {get; set;}

    // then, whenever you want to use them you access them via the Properties.
    // Let's see the example in our constructor
    public this()
        Message = "hola";        
        Name = "mundo";
        LoopMessage = 0;

6 comments:

  1. Nice! Didn't know Nemerle had a braceless syntax option!

    ReplyDelete
  2. Nemerle is really good ^_^
    But the goal is macros.

    There are some really cool tutorials from main Nemerle RSDN team (But on Russian) IF you are interestied in translation I can do it just for you :)

    ReplyDelete
  3. @nCdy

    That's exactly what I was reading about Nemerle, the Macros stuff looks very interesting and lots of examples are on the courses and tutorials out there, but I will let that for future posts; probably in a new series called... "Nemerle - Language's Strengths"? :)

    Thanks for the translation offer! :D

    ReplyDelete
  4. look here http://rsdn.ru/summary/3766.xml
    and use Google Panel and site translator there

    ReplyDelete
  5. # mutable i = 0;
    # while(i < loopMessage) {
    # Console.WriteLine("{0} {1}!", Capitalize(message),
    # Capitalize(name));
    # i++;
    # }

    This code can be rewritten (with standard macros) to:
    #using System.Console;
    #...
    # repeat(loopMessage)
    # WriteLine("$(Capitalize(message)) $(Capitalize(name))!");

    You not need add type annotation to variables:
    def dtNow = DateTime.Now;

    And you can use macro-attribute [Recort] instead write ctor.
    I.e. instead:
    # public this(message : string, name : string, loopMessage : int)
    # this.message = message;
    # this.name = name;
    # this.loopMessage = loopMessage;
    you can simply write:
    [Record] class Greet

    You accessors don't do any productive work. It can be replaced by Accessor macro:
    # [Accessor(flags = WantSetter)] mutable message : string;
    # [Accessor(flags = WantSetter)] mutable name : string;
    # [Accessor(flags = WantSetter)] mutable loopMessage : int;
    or by autoproperty:
    public Message : string { get; set; }
    ...

    ReplyDelete
  6. @nCdy

    Thanks nCdy, I just did it (http://rsdn.ru to english) and found the tutorials you were talking about. I will certainly have a look.

    @VladD2

    Thanks for your comments and suggestions Vlad. Those definitively deserve an update to the post! I will update it during the week.

    ReplyDelete