-
Notifications
You must be signed in to change notification settings - Fork 89
Features
Probably the most important feature of Nemerle is the ability to mix object oriented and functional programming styles. The top-level program structure is object oriented, while in the body of methods one can (but is not forced to) use functional style. In some programming problems this is very handy. The feature set here includes functional values, variants and pattern matching.
The other very important feature is taking a high level approach in all aspects of the language - we try to lift as much of the burden from the programmer as possible. Features like macros and type inference fit here.
Last but not least - the usage of more mundane library stuff from the .NET is as easy as (or easier than) in C#.
There is no reason you should write:
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add ("Ala", 7);
foreach (string s in args) {
...
}
when you can write:
def d = Dictionary ();
d.Add ("Ala", 7);
foreach (s in args) {
...
}
All the type information in the C# example is redundant and compiler can easily figure it out, without forcing the programmer to type it.
Some larger example shows how type inference is used together with overloading and generics.
Macros allow you to have boilerplate code generated for you under the hood, with additional static checks performed by the compiler. They give you the power to programatically generate code.
For example, using Nemerle macros for SQL you can write
ExecuteReaderLoop ("SELECT firstname, lastname FROM employee WHERE firstname = $myparm", dbcon,
{
System.Console.WriteLine ("Name: {0} {1}", firstname, lastname)
});
instead of
string sql = "SELECT firstname, lastname FROM employee WHERE firstname = :a";
NpgsqlCommand dbcmd = new NpgsqlCommand (sql, dbcon, dbtran);
dbcmd.Parameters.Add("a", myparm);
NpgsqlReader reader = dbcmd.ExecuteReader();
while(reader.Read()) {
string firstname = reader.GetString (0);
string lastname = reader.GetString (1);
System.Console.WriteLine ("Name: {0} {1}", firstname, lastname)
}
reader.Close();
dbcmd.Dispose();
and this is not just hiding some operations into a library, but additional work performed by compiler to understand the query string, variables used there, and columns returned from the database. The ExecuteReaderLoop macro will generate code roughly equivalent to what you would have to type manually. Moreover... it connects to the database at compilation time to check that your SQL query really makes sense.
Macros can analyze code, which you supply to them. For example, the $ operator can read the string literal following it:
$"My name is $Name and I am $Age years old."
and replace it with code doing what you wanted:
StringBuilder ("My name is ").Append (Name.ToString ()).Append (" and I am ")
.Append (Age.ToString ()).Append (" years old.").ToString ()
If you were using C#, you would probably write it as:
String.Format("My name is {0} and I am {1} years old.", Name, Age)
However it is less efficient, as the string has to be analyzed during runtime. Of course one should also consider:
String.Format("name {0}, age {1}, surname {2}, children-count {3}, cat-count {4}, dog count {5}",
Name, Age, Surname, ChildrenCount, CatCount, DogCount)
It is very easy to get the numbers wrong.
You probably at least once wanted to have some little special syntax in language you are using... Macros with syntax extensions can do this:
macro ReverseFor (i, begin, body)
syntax ("ford", "(", i, ";", begin, ")", body)
{
<[ for ($i = $begin; $i >= 0; $i--) $body ]>
}
defines a macro introducing the ford (EXPR ; EXPR) EXPR syntax and can be used like
ford (i ; n) print (i);
There are other examples in the Nemerle distribution -- like design by contract macros, macros for lazy evaluation or even such mundane tasks as logging. Other examples can be found at the class library documentation page.