Why did you... - vilinski/nemerle GitHub Wiki

To light a candle is to cast a shadow.
from A Wizard of Earthsea by Ursula K. Le Guin

Table of Contents

Introduction

We'll try here to answer some of controversial thoughts you might have after looking on Nemerle feature set.

Why?

Platform

Q: Why use CLI/.NET?

Mainly for interop reasons. There are number of CLI libraries and bindings out there already. There is going to be more and more.

Surely we'll loose WRT to compiled OCaml in terms of performance, at least until JIT's are made perfect, but it is easily possible to write a Gtk, GNOME, Windows GUI or even KDE application, we can embed Nemerle into ASP.NET web pages and there are more and more applications and libraries supporting .NET now. It is also possible to write libraries for other .NET languages, like C# or VB.NET.

We have also avoided significant development costs, because of this decision (no need for low-level compiler, JIT, the runtime library).

Comparing to C#...

Q: Why use Nemerle and not C#?

Nemerle is probably going to be used in some applications, where C# would be otherwise chosen. Why one would use Nemerle and not established, well described C#?

In Nemerle you can do mostly everything you would have done in C#. mostly refers to unsafe code and maybe some C-interfacing tricks. But of course you can do more:

  • Program in a functional style. It is sometimes very handy, once you get used to it. Functions are first class values so you can pass them to other functions easily (this is much like delegates but with better syntax and used more widely).
  • Variants with pattern matching. This feature is very useful when describing tree-like structures like arithmetic expressions or XML. This tends to be much shorter and clearer than in C#, and thanks to the warning about non-exhaustive matching -- much safer.
  • Syntax extensions. This feature allows programmers to customize Nemerle to their needs. If they want to have special type of loop or some notational shortcut, they just add it to the language.
  • Macros allow you to add compile-time executed code to your program. This gives wide range of possibilities to verify Domain-specific languages (like SQL, regular expressions) employed by the project. Using Aspects-oriented programming (being implemented with macros) allows skilled programmers to write programs operating on classes and saves everyone typing the same methods for the Nth time for the Nth class.
  • Type inference allows much easier prototyping and makes code shorter (less to read and type):
Foo.Bar_long_name <Baz.Qux> x = 
  new Foo.Bar_long_name <Baz.Qux> (10)

you write:

def x = Foo.Bar_long_name (10)

Comparing to F# and SML.NET...

Q: Why use Nemerle and not F# or SML.NET?

F# is a .NET port of subset of OCaml. SML.NET is Standard ML '97 implementation for the .NET. Both are languages from the ML family.

We believe Nemerle is far easier to grasp for programmer who has not been exposed to ML-like languages before (due to more bracy syntax and a few other design choices). At the same time the functional capabilities provided by the three languages are mostly the same.

Nemerle is a new language. We had CLS interop in mind since the very beginning. OTOH both SML.NET and F# are ports of existing languages, with a retrofitted CLS layer. In our opinion this does not play that well together.

Dynamic types

Q: Why dynamic types? Don't they impact performance?

By dynamic types we understand the fact that all values carry runtime types. These types can be queried during runtime, and dynamic casts can be performed, raising exceptions in case of type mismatch.

Probably yes. But dynamic types are inherent part of CLI so there is no performance reason to ban them (we would have to pay performance cost anyway). Additionally, dynamic types are useful in some contexts, like dynamic loading of classes (or rather dynamic construction of objects).

For example what static type would you give to polymorphic de-serialization function? In OCaml it has type in_channel -> 'a which is obviously wrong.

Of course there are several religious issues about dynamic typing. Our answer is very simple: you don't need dynamic types -- don't use them.

Macros and syntax extensions

Q: What syntax extensions are good for? Programmers are writing in languages not writing languages.

Not so! :-) Programmers in every language have their own ideas about how to fix one annoying "feature" or another of their language. Macros give the programmer a way to make up for the shortcomings and oversights of the designers of their language.

Of course, not everybody will use them, but we intend to provide a library of useful language extensions along with Nemerle. See some interesting examples.

Macros give you a powerful tool for research in programming languages design and implementation of new ideas like Join Calculus. You need not create an entire compiler from scratch, but simply write a function transforming code and include a using My.NewLanguageFeature; directive in the final program.

It is possible to define functions that we're unable to encode in our type-system. Ordinary example is C-like, but type-safe printf function.

Nemerle also allows extending language syntax to some degree, though probably not in the Right Way. It allows introducing keyword patterns and deferring parsing of parts of the token stream.

Syntax questions

This section will try to answer a few questions about the Nemerle syntax, and sometimes semantics behind it.

Function call requires ()

 Q: Why does function call require <code>()</code>? <code>f x</code> looks
    much better than <code>f(x)</code>, and in ML you can use both forms.

Function call requires (). It looks like this:

f (x, y, z);
f (x);
f ();

Form without () (i.e. f x) is not allowed.

There are some good reasons for that. The main one is that it allows for better overloading resolution (simply when looking at f (x, y) you know you need a function with 2 parameters, and it's not a partial application). Overloading is likely to occur quite frequently in CLI. Another reason is that following code will give you a parse error, not a weird typing error:

f (x)  /* forgot ';' here */
g (x)

Using this syntax it is not possible to do partial application, but see below.

null value

 Q: There is a special <code>'a option</code> type in ML, which can be
    <code>Some x</code> or <code>None</code> and is used where a pointer, that

can be null, would have been used in C-like languages. So what

    is <code>null</code> value good for? You can have <code>option</code>

type in Nemerle too.

Of course you can, you even have it in standard library. It's the suggested way of handling this matter.

But think about external functions that can return references. By CLI standards they can also return null. Thus it would require to have all functions returning foo in CLI to return option (foo) in Nemerle, and you would end up using val_of function over and over again, resulting in None_value (or something) exceptions instead of System.NullReferenceException.

This is why we have null in the language. In fact it is quite common in Nemerle to have a feature just for interop reasons.

Sequence in {}

 Q: Why a sequence needs to be enclosed in <code>{}</code>? Wouldn't it
    be possible to assign some priority to the <code>;</code> operator

and treat this as an expression?

It would be possible, but it's quite error-prone and misleading. In simple examples it's OK:

let x = 3 in g x; h x /* Caml */
{ def x = 3; g (x); h (x) }     /* Nemerle */

But consider the following snippet of Caml:

/* Correct */
if x > y then
  let x = 3 in
  f x;
  g x
else
  h ()

/* Parse error */
if x > y then
  f 3;
  g 3
else 
  h ()

Thanks to ; being used only in clear context it is not possible in Nemerle.

This issue is resolved in similar manner in OCaml Revised Syntax.

if requires else

 Q: Why does <code>if</code> require <code>else</code>? In OCaml one doesn't
    need to write <code>else ()</code>.

To avoid confusing grammar ambiguities. Besides, this is a functional language, what is if expression without else?

You can also use when and unless macros for if without else or else without if.

Where did X go?

A few explanations about how to do various things in Nemerle.

Partial application

Q: How to make a partial function application?

You simply need to use the so called eta-long form:

def f (x, y) { ... };
def g (x) { fun (y) { f (x, y) } };

def plus5 (x) { fun (x) { 5 + x } };

This prevents partial application bugs, which would be common in presence of overloading.

We have however a powerful --notion that subsumes partial application.

⚠️ **GitHub.com Fallback** ⚠️