Methods
fun
declares methods. Methods must have a name, may have parameters, and may have a return type. Parameters are typed; however, a single type can be used for multiple parameters.
fun foo(x, y: Int, s: String): Bool # ...
do
declares the body of methods. Alike control structures, a one-liner version is available.
Therefore, the two following methods are equivalent.
fun next1(i: Int): Int do return i + 1 end fun next2(i: Int): Int do return i + 1
Inside the method body, parameters are considered as variables. They can be assigned and are subject to adaptive typing.
self
, the current receiver, is a special parameter. It is not assignable but is subject to adaptive typing.
return
exits the method and returns to the caller. In a function, the return value must be provided with a return in all control flow paths.
Method Call
Calling a method is usually done with the dotted notation x.foo(y, z)
. The dotted notation can be chained.
A method call with no argument does not need parentheses. Moreover, even with arguments, the parentheses are not required in the principal method of a statement.
var a = [1] a.add 5 # no () for add print a.length # no () for length, no () for print
However, this last facility requires that the first argument does not start with a parenthesis or a bracket.
foo (x).bar # will be interpreted as (foo(x)).bar foo [x].bar # will be interpreted as (foo[x]).bar
Method Redefinition
redef
denotes methods that are redefined in subclasses or in class refinements. The number and the types of the parameters must be invariant. Thus, there is no need to reprecise the types of the parameters, only names are mandatory.
The return type can be redefined to be a more precise type. If same type is returned, there is no need to reprecise it.
The visibility, also, cannot be changed, thus there is also no need to reprecise it.
class Foo # implicitly an Object # therefore inherit '==' and 'to_s' var i: Int redef fun to_s do return "Foo{self.i}" redef fun ==(f) do return f isa Foo and f.i == self.i end
Abstract Methods
is abstract
indicates methods defined without a body. Subclasses and refinements can then redefine it (the redef
is still mandatory) with a proper body.
interface Foo fun derp(x: Int): Int is abstract end class Bar super Foo redef fun derp(x) do return x + 1 end
Concrete classes may have abstract methods. It is up to a refinement to provide a body.
Call to Super
super
calls the “previous” definition of the method. It is used in a redefinition of a method in a subclass or in a refinement, It can be used with or without arguments; in the latter case, the original arguments are implicitly used.
The super
of Nit behaves more like the call-next-method
of CLOS than the super
of Java or Smalltalk. It permits the traversal of complex class hierarchies and refinement. Basically, super
is polymorphic: the method called by super
is not only determined by the class of
definition of the method, but also by the dynamic type of self
.
The principle is to produce a strict order of the redefinitions of a method (the linearization). Each call to super
call the next method definition in the linearization. From a technical point of view, the linearization algorithm used is based on C3. It ensures that:
A definition comes after its redefinition.
A redefinition in a refinement comes before a redefnition in its superclass.
The order of the declaration of the superclasses is used as the ultimate disambiguation.
class A fun derp: String do return "A" end class B super A redef fun derp do return "B" + super end class C super A redef fun derp do return "C" + super end class D super B super C redef fun derp do return "D" + super # Here the linearization order of the class D is DBCA # D before B because D specializes B # B before A because B specializes A # D before C because D specializes C # C before A because C specializes A # B before C because in D 'super B' is before 'super C' end var b = new B print b.derp # outputs "BA" var d = new D print d.derp # outputs "DBCA"
Operators and Setters
Operators and setters are methods that require a special syntax for their definition and their invocation.
binary operators:
+
,-
,*
,/
,\%
,==
,<
,>
,<=
,>=
,<<
,>>
and<=>
. Their definitions require exactly one parameter and a return value. Their invocation is done withx + y
wherex
is the receiver,+
is the operator, andy
is the argument.unary operator:
-
. Its definition requires a return value but no parameter. Its invocation is done with-x
wherex
is the receiver.bracket operator:
[]
. Its definition requires one parameter or more and a return value. Its invocation is done withx[y, z]
wherex
is the receiver,y
the first argument andz
the second argument.setters:
something=
wheresomething
can be any valid method identifier. Their definitions require one parameter or more and no return value. If there is only one parameter, the invocation is done withx.something = y
wherex
is the receiver andy
the argument. If there is more that one parameter, the invocation is done withx.something(y, z) = t
wherex
is the receiver,y
the first argument,z
the second argument andt
the last argument.bracket setter:
[]=
. Its definition requires two parameters or more and no return value. Its invocation is done withx[y, z] = t
wherex
is the receiver,y
the first argument,z
the second argument andt
the last argument.
class Foo fun +(a: Bar): Baz do ... fun -: Baz do ... fun [](a: Bar): Baz do ... fun derp(a: Bar): Baz do ... fun derp(a: Bar, b: Baz) do ... fun []= (a: Bar, b: Baz) do ... end var a: Foo = ... var b: Bar = ... var c: Baz = ... c = a + b c = -b c = a[b] # The bracket operator '[]' c = a.derp(b) # A normal method 'derp' a.derp(b) = c # A setter 'derp' a[b] = c # The bracket setter '[]='
+=
and -=
are combinations of the assignment (=
) and a binary operator. These feature are extended to setters where a single +=
is in fact three method calls: a function call, the operator call, then a setter call.
a += c # equiv. a = a + c a[b] += c # equiv. a[b] = a[b] + c a.foo += c # equiv. a.foo = a.foo + c a.bar(b) += c # equiv. a.bar(b) = a.bar(b) + c
Variable Number of Arguments
A method can accept a variable number of arguments using ellipsis (...
). The definition use x: Foo...
where x
is the name of the parameter and Foo
a type. Inside the body, the static type of x
is Array[Foo]
. The caller can use 0, 1, or more arguments for the parameter x
. Only one ellipsis is allowed in a signature.
fun foo(x: Int, y: Int..., z: Int) do print "{x};{y.join(",")};{z}" end foo(1, 2, 3, 4, 5) # outputs "1;2,3,4;5" foo(1, 2, 3) # outputs "1;2;3"
Top-level Methods and Main Body
Some functions, like print
, are usable everywhere simply without using a specific receiver. Such methods are just defined outside any classes. In fact, these methods are implicitly defined in the
Object
interface, therefore inherited by all classes, therefore usable everywhere. However, this principle may change in a future version.
In a module, the main body is a bunch of statements at the end of a file. The main body of the main module is the program entry point. In fact, the main method of a program is implicitly defined as the redefinition of the method main
of the Sys
class; and the start of the program is the implicit statement (Sys.new).main
. Note that because it is a redefinition, the main part can use super
to call the “previous” main part in the imported modules. If there is no main part
in a module, it is inherited from imported modules.
Top-level methods coupled with the main body can be used to program in a pseudo-procedural way. Therefore, the following programs are valid:
print "Hello World"
fun sum(i, j: Int): Int do return i + j end print sum(4, 5)
Intern and Extern Methods
intern
and extern
indicate concrete methods whose body is not written in Nit.
The body of intern
methods is provided by the compiler itself for performance or bootstrap reasons. For the same reasons, some intern methods, like +
in Int
are not redefinable.
The body of extern
methods is provided by libraries written in C; for instance, the system libraries required for input/output. Extern methods are always redefinable. See FFI for more information on extern
methods.