Nemerle

Last updated
Nemerle
Paradigm Multi-paradigm: aspect-oriented, event-driven, functional, generic, imperative, meta, object-oriented, reflective
Family C#
Designed by Kamil Skalski, Michał Moskal, Prof. Leszek Pacholski, Paweł Olszta at Wrocław University
Developer JetBrains (formerly)
RSDN
First appeared2003;20 years ago (2003)
Stable release
1.2.507.0 [1] / 6 August 2016;6 years ago (2016-08-06)
Typing discipline Inferred, nominal, static, strong
Platform CLI
Filename extensions .n
Website nemerle.org
Major implementations
Nemerle
Influenced by
C#, Lisp, ML

Nemerle is a general-purpose, high-level, statically typed programming language designed for platforms using the Common Language Infrastructure (.NET/Mono). It offers functional, object-oriented, aspect-oriented, reflective and imperative features. It has a simple C#-like syntax and a powerful metaprogramming system.

Contents

In June 2012, the core developers of Nemerle were hired by the Czech software development company JetBrains. The team was focusing on developing Nitra, a framework to implement extant and new programming languages. [2] [3] [4] Both the Nemerle language and Nitra have seemingly been abandoned or discontinued by JetBrains; Nitra has not been updated by its original creators since 2017 and Nemerle is now maintained entirely by the Russian Software Development Network, independently from JetBrains, although no major updates have been released yet and development is progressing very slowly. Neither Nemerle, nor Nitra have been mentioned or referenced by JetBrains for years.

Nemerle is named after the Archmage Nemmerle, a character in the fantasy novel A Wizard of Earthsea by Ursula K. Le Guin.

Features

Nemerle's most notable feature is the ability to mix styles of programming that are object-oriented and functional. Programs may be structured using object-oriented concepts such as classes and namespaces, while methods can (optionally) be written in a functional style. Other notable features include:

The metaprogramming system allows for great compiler extensibility, embedding domain-specific languages, partial evaluation, and aspect-oriented programming, taking a high-level approach to lift as much of the burden as possible from programmers. The language combines all Common Language Infrastructure (CLI) standard features, including parametric polymorphism, lambdas, extension methods etc. Accessing the libraries included in the .NET or Mono platforms is as easy as in C#.

Type inference

defx=1;// intdefmyList=List();// generic List[T], type T is deduced from the usage in the next linemyList.Add(x);// compiler deduces type of T as int making myList type of List[int]

Everything is an expression

defx={// similar to x = 3defy=1;defz=2;y+z// this last statement is a block return value};defx=if(DateTime.Now.DayOfWeek==DayOfWeek.Monday)// if, using, try are also expressions"Monday"else"other day";defx=tryint.Parse(someString)catch{|FormatException()=>0};defx=returnBlock:{foreach(iin[1,2,3])when(i>2)returnBlock(true);// exit block (x = true)false// x = false};

Tuples

defk=(1,"one");// k : (int * string)def(a,b)=k;// a = 1, b = "one"

Pattern matching

defresult=match(number){|0=>"zero"|1=>"one"|xwhenx<0=>"negative"|_=>"more than one"}
Other pattern matching examples

Type matching with variable binding:

defcheck(o:object){match(o){|iisint=>$"An int: $i"|sisstring=>$"A string: $(s.ToUpper())"|_=>"Object of another type"}}

Tuple pattern matching:

match(tuple){|(42,_)=>"42 on first position"|(_,42)=>"42 on second position"|(x,y)=>$"( $x, $y )"}

Regexp matching:

usingNemerle.Text;regexpmatch(str){|"a+.*"=>printf("a\n");|@"(?<num : int>\d+)-\w+"=>printf("%d\n",num+3);|"(?<name>(Ala|Kasia))? ma kota"=>match(name){|Some(n)=>printf("%s\n",n)|None=>printf("noname?\n")}|_=>printf("default\n");}

Functional types and local functions

usingSystem.Console;// classes and modules (static classes) can be put in namespacesdefnext(x){x+1};// the type of x argument and other function arguments can be deduced from usagedefmult(x,y){x*y};deffibonacci(i){|0=>0|1=>1|other=>fibonacci(i-1)+fibonacci(i-2)};WriteLine(next(9));// 10  similar to "Console.WriteLine(next(9));" WriteLine(mult(2,2));// 4WriteLine(fibonacci(10));// 55

Variants

Variants (called data types or sum types in SML and OCaml) are forms of expressing data of several different kinds:

variantRgbColor{|Red|Yellow|Green|Different{red:float;green:float;blue:float;}}

Metaprogramming

Nemerle's macro system allows for creating, analysing, and modifying program code during compiling. Macros can be used in the form of a method call or as a new language construct. Many constructs within the language are implemented using macros (if, for, foreach, while, using etc.).

"if" macro example:

macro@if(cond,e1,e2)syntax("if","(",cond,")",e1,Optional(";"),"else",e2){/*    <[ ]> defines an area of quasi-quotation, the Nemerle compiler transforms the code in it     to an AST, such transformations are somewhat similar to an Expression compiling in C#  */<[match($cond:bool){|true=>$e1|_=>$e2}]>}// using this macro in code:defmax=if(a>b)aelseb;// during a compile time the upper line will be transformed to this:defmax=match(a>b){|true=>a|_=>b}

Braceless syntax

Similarly to the braceless syntax later added to Scala, Nemerle allows the programmer to optionally use a whitespace-sensitive syntax based on the off-side rule, similarly to Python.

The following curly-brace snippet:

usingSystem.Console;[Qux]classFooBar{publicstaticMain():void{WriteLine("Hello")}staticFoo(x:int):void{if(x==3){defy=x*42;Foo(x)}else{[x].Map(fun(x){x*2})}}staticBar():int{deffoo=2+7*13;foo}}

could be rewritten as:

usingSystem.Console;[Qux]\classFooBarpublicstaticMain():voidWriteLine("Hello")staticFoo(x:int):voidif(x==3)defy=x*42;Foo(x)else[x].Map(fun(x){x*2})staticBar():intdeffoo=2+7*13foo

Notably, it is not possible to break expressions or alternative clauses in matches over multiple lines without using a backslash \:

// This will not compile ...staticBar():intdeffoo=2+7*13foomatch(s)|"a"|"aa"=>1|"b"|"bb"=>2|_=>0// But this will:staticBar():intdeffoo=2\+7\*13foomatch(s)|"a"\|"aa"=>1|"b"\|"bb"=>2|_=>0

In order to activate this syntax, the user must add #pragma indent to the top of the file or use the compiler option -i.

IDE

Nemerle can be integrated into the integrated development environment (IDE) Visual Studio 2008. It also has a fully free IDE based on Visual Studio 2008 Shell [5] (like Visual Studio Express Editions) and SharpDevelop (link to plugin source code).

Nemerle can be also integrated into Visual Studio (up until 2017) using add-ins and extensions. [6]

Examples

Hello, World!

The traditional Hello World! can be implemented in a more C#-like fashion:

classHello{staticMain():void{System.Console.WriteLine("Hello, world!");}}

or more simply:

System.Console.WriteLine("Hello, world!");

Examples of macros

Macros allow generating boilerplate code with added static checks performed by the compiler. They reduce the amount of code that must be written by hand, make code generation safer, and allow programs to generate code with compiler checks, while keeping source code relatively small and readable.

String formatting

The string formatting macro simplifies variables to string manipulations using $ notation:

defs=$"The number is $i";//insert the value of the variable i where $i is placed defs=$"$x + $y = $(x+y)";// $(...) can be used to make calculations or access members

Declarative code generation

StructuralEquality, Memoize, json, and with are macros which generate code in compile time. Though some of them (StructuralEquality, Memoize) can look like C# attributes, during compiling, they will be examined by the compiler and transformed to appropriate code using logic predefined by their macros.

[StructuralEquality]// Implement IEquatable[Sample] .Net interface using by element comparison equality.classSample{[Memoize]// remember first evaluation result publicstaticSomeLongEvaluations():int{MathLib.CalculateNthPrime(10000000)}[DependencyProperty]// WPF dependency propertypublicDependencyPropertySample{get;set;}publicstaticMain():void{/* syntax macro "json" generates code: JObject.Object([("a", JValue.Number(SomeLongEvaluations())), ("b", JValue.Number(SomeLongEvaluations() + 1))])*/defjObject=json{a:SomeLongEvaluations();b:(SomeLongEvaluations()+1)}// object initialization macro "<-" is development of C# curly brackets object initializationdefk=Diagnostics.Process()<-{StartInfo<-// can init inner objects properties without ctor call{FileName="calc.exe";UseShellExecute=true;}Exited+=()=>WriteLine("Calc done");// events and delegates}ReadLine();}}

Database accessibility

Using Nemerle macros for SQL you can write:

ExecuteReaderLoop("SELECT firstname, lastname FROM employee WHERE firstname = $myparm",dbcon,{WriteLine($"Name: $firstname$lastname")});

instead of

stringsql="SELECT firstname, lastname FROM employee WHERE firstname = :a";using(NpgsqlCommanddbcmd=newNpgsqlCommand(sql,dbcon,dbtran)){dbcmd.Parameters.Add("a",myparm);using(NpgsqlReaderreader=dbcmd.ExecuteReader()){while(reader.Read()){varfirstname=reader.GetString(0);varlastname=reader.GetString(1);Console.WriteLine("Name: {0} {1}",firstname,lastname)}}}

and this is not just hiding some operations in a library, but additional work performed by the compiler to understand the query string, the variables used there, and the 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.

New language constructs

With Nemerle macros you can also introduce some new syntax into the language:

macroReverseFor(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);

Nemerle with ASP.NET

Nemerle can be either embedded directly into ASP.NET:

<%@PageLanguage="Nemerle"%><scriptrunat="server">Page_Load(_:object,_:EventArgs):void{Message.Text=$"You last accessed this page at: $(DateTime.Now)";}EnterBtn_Click(_:object,_:EventArgs):void{Message.Text=$"Hi $(Name.Text), welcome to ASP.NET!";}</script><html><body><formrunat="server">             Please enter your name: <asp:TextBoxID="Name"runat="server"/><asp:ButtonOnClick="EnterBtn_Click"Text="Enter"runat="server"/><p><asp:LabelID="Message"runat="server"/></p></form></body></html>

...Or stored in a separate file and entered with a single line:

<%@PageLanguage="Nemerle"Src="test.n"Inherits="Test"%>

PInvoke

Nemerle can take advantage of native platform libraries. The syntax is very similar to C#'s and other .NET languages. Here is the simplest example:

usingSystem;usingSystem.Runtime.InteropServices;classPlatformInvokeTest{[DllImport("msvcrt.dll")]publicexternstaticputs(c:string):int;[DllImport("msvcrt.dll")]internalexternstatic_flushall():int;publicstaticMain():void{_=puts("Test");_=_flushall();}}

Related Research Articles

Common Intermediate Language (CIL), formerly called Microsoft Intermediate Language (MSIL) or Intermediate Language (IL), is the intermediate language binary instruction set defined within the Common Language Infrastructure (CLI) specification. CIL instructions are executed by a CLI-compatible runtime environment such as the Common Language Runtime. Languages which target the CLI compile to CIL. CIL is object-oriented, stack-based bytecode. Runtimes typically just-in-time compile CIL instructions into native code.

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

The C preprocessor is the macro preprocessor for the C, Objective-C and C++ computer programming languages. The preprocessor provides the ability for the inclusion of header files, macro expansions, conditional compilation, and line control.

In mathematics and computer science, a higher-order function (HOF) is a function that does at least one of the following:

The syntax of the C programming language is the set of rules governing writing of software in the C language. It is designed to allow for programs that are extremely terse, have a close relationship with the resulting object code, and yet provide relatively high-level data abstraction. C was the first widely successful high-level language for portable operating-system development.

A function pointer, also called a subroutine pointer or procedure pointer, is a pointer that points to a function. As opposed to referencing a data value, a function pointer points to executable code within memory. Dereferencing the function pointer yields the referenced function, which can be invoked and passed arguments just as in a normal function call. Such an invocation is also known as an "indirect" call, because the function is being invoked indirectly through a variable instead of directly through a fixed identifier or address.

<span class="mw-page-title-main">Foreach loop</span> Control flow statement for traversing items in a collection

In computer programming, foreach loop is a control flow statement for traversing items in a collection. foreach is usually used in place of a standard for loop statement. Unlike other for loop constructs, however, foreach loops usually maintain no explicit counter: they essentially say "do this to everything in this set", rather than "do this x times". This avoids potential off-by-one errors and makes code simpler to read. In object-oriented languages, an iterator, even if implicit, is often used as the means of traversal.

In mathematics and in computer programming, a variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments. Support for variadic functions differs widely among programming languages.

In some programming languages, const is a type qualifier that indicates that the data is read-only. While this can be used to declare constants, const in the C family of languages differs from similar constructs in other languages in being part of the type, and thus has complicated behavior when combined with pointers, references, composite data types, and type-checking. In other languages, the data is not in a single memory location, but copied at compile time on each use. Languages which utilize it include C, C++, D, JavaScript, Julia, and Rust.

Exception handling syntax is the set of keywords and/or structures provided by a computer programming language to allow exception handling, which separates the handling of errors that arise during a program's operation from its ordinary processes. Syntax for exception handling varies between programming languages, partly to cover semantic differences but largely to fit into each language's overall syntactic structure. Some languages do not call the relevant concept "exception handling"; others may not have direct facilities for it, but can still provide means to implement it.

The C and C++ programming languages are closely related but have many significant differences. C++ began as a fork of an early, pre-standardized C, and was designed to be mostly source-and-link compatible with C compilers of the time. Due to this, development tools for the two languages are often integrated into a single product, with the programmer able to specify C or C++ as their source language.

Haxe is an open source high-level cross-platform programming language and compiler that can produce applications and source code, for many different computing platforms from one code-base. It is free and open-source software, released under the MIT License. The compiler, written in OCaml, is released under the GNU General Public License (GPL) version 2.

In computer programming, an anonymous function is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to higher-order functions or used for constructing the result of a higher-order function that needs to return a function. If the function is only used once, or a limited number of times, an anonymous function may be syntactically lighter than using a named function. Anonymous functions are ubiquitous in functional programming languages and other languages with first-class functions, where they fulfil the same role for the function type as literals do for other data types.

In software engineering, a fluent interface is an object-oriented API whose design relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language (DSL). The term was coined in 2005 by Eric Evans and Martin Fowler.

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

In programming languages, a label is a sequence of characters that identifies a location within source code. In most languages, labels take the form of an identifier, often followed by a punctuation character. In many high-level languages, the purpose of a label is to act as the destination of a GOTO statement. In assembly language, labels can be used anywhere an address can. Also in Pascal and its derived variations. Some languages, such as Fortran and BASIC, support numeric labels. Labels are also used to identify an entry point into a compiled sequence of statements.

In computer programming, string interpolation is the process of evaluating a string literal containing one or more placeholders, yielding a result in which the placeholders are replaced with their corresponding values. It is a form of simple template processing or, in formal terms, a form of quasi-quotation. The placeholder may be a variable name, or in some languages an arbitrary expression, in either case evaluated in the current context.

In software engineering, the module pattern is a design pattern used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept.

Objective-C is a general-purpose, object-oriented programming language that adds Smalltalk-style messaging to the C programming language. Originally developed by Brad Cox and Tom Love in the early 1980s, it was selected by NeXT for its NeXTSTEP operating system. Due to Apple macOS’s direct lineage from NeXTSTEP, Objective-C was the standard programming language used, supported, and promoted by Apple for developing macOS and iOS applications until the introduction of the Swift programming language in 2014.

<span class="mw-page-title-main">Nim (programming language)</span> Programming language

Nim is a general-purpose, multi-paradigm, statically typed, compiled systems programming language, designed and developed by a team around Andreas Rumpf. Nim is designed to be "efficient, expressive, and elegant", supporting metaprogramming, functional, message passing, procedural, and object-oriented programming styles by providing several features such as compile time code generation, algebraic data types, a foreign function interface (FFI) with C, C++, Objective-C, and JavaScript, and supporting compiling to those same languages as intermediate representations.

References

  1. Nemerle 1.2.507.0
  2. "Twitter / orangy: We've decided to bring Nemerle". Twitter.com. Retrieved 2013-09-05.
  3. "JetBrains .NET Tools Blog » JetBrains and Nemerle". Blogs.jetbrains.com. 2012-06-27. Retrieved 2013-09-05.
  4. "Google Discussiegroepen" . Retrieved 2013-09-05.
  5. Nemerle Studio Microsoft Setup Installer can be installed after installing Visual Studio Shell 2008 Isolated
  6. Visual Studio 2010 add-in

Further reading