Projects.Ink History
Hide minor edits - Show changes to markup
See InkCodeScratchBook for my attempts to write interesting Ink code snippets, and InkSyntax for my attempts at writing a syntax reference and grammar for Ink.
Related documents:
- InkCodeScratchBook for my attempts to write interesting Ink code snippets
- InkSyntax for my attempts at writing a syntax reference and grammar for Ink
- MultiMethods, for a page collecting information on multi methods dispatching
- http://lambda.weblogs.com/discuss/msgReader$11988 UML and DSL a small comment by EhudLamm? on an article related to UML and DSL which I find close to the perspective I have in designing Ink.
Here is a very intersting library for Python which allows transparent access to C functions:
- http://starship.python.net/crew/theller/ctypes/ CTypes, seems like a very straightforward way to use foreign libraries in a Python program. This could be adapted to Ink as well.
abstractExpr(1)
abstractExpr (1)
abstractExpr(1,2)
abstractExpr (1,2)
abstractExpr( _, 2 )
abstractExpr ( _, 2 )
abstractExpr( b = 2 )
abstractExpr ( b = 2 )
See InkCodeScratchBook for my attemps to write interesting Ink code snippets.
See InkCodeScratchBook for my attempts to write interesting Ink code snippets, and InkSyntax for my attempts at writing a syntax reference and grammar for Ink.
See ScratchBook? for my attemps to write interesting Ink code snippets.
See InkCodeScratchBook for my attemps to write interesting Ink code snippets.
See ScratchBook? for my attemps to write interesting Ink code snippets.
Specifying constraints
3. Object model
For now, you may wonder what this mechanism is called a template system, as it does not seem to be more than a way to represent blocks of code as primitive types.
Ink supports object-oriented design. As we presented it, the basic elements of Ink are types and relations. Roughly, types can be considered as classes, and relations as functions that can be bound to classes.
Ink template system is used to define arguments to any abstract expression, and more specifically for relations. In Ink paradigm, there can be multiple abstract expressions bound to the same relation name. For instance, we could consider the join relation as follows :
For instance, looking back at our Point class, we could have declared the type as follows:
relation [a] join [b]: ...
type Point:
annotations are (basic, immutable)
structure is (
x : type Number
y : type Number
)
relations are (
add! [p:Point]:
point := Point create
point.x = .x
point.y = .y
[point]
)
which would evaluate this way
Here we can notice two things:
1 join 2 --> 12
- The left member of the relation
addwas omitted - The
.xand.yexpressions have an implicit left member, which a value of the current type.
"Hello" join "World" --> "Hello World"
This notation is stricly equivalent to the form we presented above, it is expanded by the Ink compiler in the same way.
In this case, we see that the join relation is an abstract expression with two arguments, but the same relation produces different results with different concrete arguments.
2.1 Data encapsulation
So the question is, how to declare a relation, or abstract expression to behave differently according to the given arguments ? This is the purpose of the template system : conditionnaly conretize abstract expression according to a specific logic. This what makes Ink template system a system.
One of the basic mechanisms required by object-oriented design is encapsulation. Encapsulation means that direct access to an object internal state is forbidden, and always go through a set of accessors. Accessors are interface between the object internal state and the environment.
Abstract expression can be conditionnaly expanded according to constraints. The above cases could be defined as follows :
Accessors are split between accessors and mutators. An accessor allows to access the value of a part of the object state, while a mutator allows to change this value.
relation [a:as Number] join [b:as Number]: [a * 10 + b ]
Here is an example of accessors for the upper-left attribute of the Rectangle type:
relation [a:as String] join [b:as String]: [a + " " + b ]
type Rectangle:
structure is (
upper-left: type Point
lower-right: type Point
)
The argument templates have now been expanded with a type constraint on every argument.
.upper-left access is:
[.upper-left]
.upper-left mutate! <p:Point> is:
.upper-left = p
We could go further and specify different relations depending on the values of certain arguments :
Now, the data structure attributes can be simply accessed:
relation [a:as Number, < 10] join [b: as Number, <10]:
[a * 10 + b]
r := Rectangle create r.upper-left = Point create (1, 1) r.lower-right = Point create (2, 2) print r.lower-right.x
relation [a:as Number, < 10] join [b: as Number, <100]:
[a * 100 + b]
--> 2
relation [a:as Number, < 10] join [b: as Number, <1000]:
[a * 1000 + b]
2.2 Polymorphism
you can note that it is not required to specify constraints such as b>10 for the second relation, as the relations are evaluated sequentially, in their reverse order of declaration, until one is matched.
A second important point of object-orientation is polymorphism.
How to determine to order constraints ? Which are more generic, or less generic ?
Polymorphism is handled in two different ways in Ink. The first one is by explicit typing: you simply express to which specific types a relation will apply. The other way is by expressing constraints on a value: what structure it should have, which annotations its type should have, and so on.
Polymorphism is then easily realised by specifying constraints on the parameters of a relation. Consider the following examples:
[p!:Point] add [p2:Point]: p : (.x, .y) = p2 : (.x, .y)
3. Object model
[p!:.x Number, .y Number] add [p:.x Number, .y Number] p : (.x, .y) = p2 : (.x, .y)
Ink supports object-oriented design. As we presented it, the basic elements of Ink are types and relations. Roughly, types can be considered as classes, and relations as functions that can be bound to classes.
[p!] add [p2] p : (.x, .y) = p2 : (.x, .y)
For instance, looking back at our Point class, we could have declared the type as follows:
The above declarations seem all similar, but only their process is similar: they apply to different types of values.
type Point:
annotations are (basic, immutable)
structure is (
x : type Number
y : type Number
)
relations are (
add! [p:Point]:
point := Point create
point.x = .x
point.y = .y
[point]
)
- First expression only applies to
Pointvalues - Second expression applies to any value which as
xandyattributes of typeNumber - Third expression applies to any values which have
xandyattributes.
Here we can notice two things:
Actually, there is one more constraint for the two last constraints : there must exist a mutator for the x attribute of the left member that accepts the value of the x attribute of the right member, and this is the same for the y attribute.
- The left member of the relation
addwas omitted - The
.xand.yexpressions have an implicit left member, which a value of the current type.
Scoping rules
This notation is stricly equivalent to the form we presented above, it is expanded by the Ink compiler in the same way.
Design patterns
2.1 Data encapsulation
Concurrency
One of the basic mechanisms required by object-oriented design is encapsulation. Encapsulation means that direct access to an object internal state is forbidden, and always go through a set of accessors. Accessors are interface between the object internal state and the environment.
Application operator and template system
Accessors are split between accessors and mutators. An accessor allows to access the value of a part of the object state, while a mutator allows to change this value.
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Here is an example of accessors for the upper-left attribute of the Rectangle type:
If we go back to our point addition relation, we see the following block of code:
type Rectangle:
structure is (
upper-left: type Point
lower-right: type Point
)
point.x = p1.x + p2.x point.y = p1.y + p2.y
.upper-left access is:
[.upper-left]
.upper-left mutate! <p:Point> is:
.upper-left = p
Can be rewritten :
Now, the data structure attributes can be simply accessed:
(x, y) : <a> point.a = p1.a + p2.a
r := Rectangle create r.upper-left = Point create (1, 1) r.lower-right = Point create (2, 2) print r.lower-right.x
The application operator is a bit like the shell | operator: you apply the right member of the | to the output of the evaluation of the left member.
--> 2
Pattern-Matching
2.2 Polymorphism
The following examples adds any list that starts with two Number values to the point:
A second important point of object-orientation is polymorphism.
relation [p:Point] add ([x:Number], [y:Number], _ )
Polymorphism is handled in two different ways in Ink. The first one is by explicit typing: you simply express to which specific types a relation will apply. The other way is by expressing constraints on a value: what structure it should have, which annotations its type should have, and so on.
can also be written:
Polymorphism is then easily realised by specifying constraints on the parameters of a relation. Consider the following examples:
relation [p:Point] add ([x,y:Number], _ )
[p!:Point] add [p2:Point]: p : (.x, .y) = p2 : (.x, .y)
Syntax overview
[p!:.x Number, .y Number] add [p:.x Number, .y Number] p : (.x, .y) = p2 : (.x, .y)
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
[p!] add [p2] p : (.x, .y) = p2 : (.x, .y)
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
The above declarations seem all similar, but only their process is similar: they apply to different types of values.
Relation naming convention
- First expression only applies to
Pointvalues - Second expression applies to any value which as
xandyattributes of typeNumber - Third expression applies to any values which have
xandyattributes.
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
Actually, there is one more constraint for the two last constraints : there must exist a mutator for the x attribute of the left member that accepts the value of the x attribute of the right member, and this is the same for the y attribute.
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
Scoping rules
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
Design patterns
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
Concurrency
Parameters naming convention
Application operator and template system
Formal parameters in relations must be suffixed by ! when the given parameter value is mutated. By default, parameters are immutable, unless they are indicated as mutable by the ! suffix.
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
If we go back to our point addition relation, we see the following block of code:
point.x = p1.x + p2.x point.y = p1.y + p2.y
Can be rewritten :
(x, y) : <a> point.a = p1.a + p2.a
The application operator is a bit like the shell | operator: you apply the right member of the | to the output of the evaluation of the left member.
Pattern-Matching
The following examples adds any list that starts with two Number values to the point:
relation [p:Point] add ([x:Number], [y:Number], _ )
can also be written:
relation [p:Point] add ([x,y:Number], _ )
Syntax overview
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
Relation naming convention
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
Parameters naming convention
Formal parameters in relations must be suffixed by ! when the given parameter value is mutated. By default, parameters are immutable, unless they are indicated as mutable by the ! suffix.
return clone
[clone]
2. Template system
2. Templating system
One of the particularities of Ink is to embed within the language itself a simple but effective templating system. In fact, any Ink expression or construct can be either concrete or abstract, which are defined as followed.
3. Object model
A concrete expression is an expression which can be directly evaluated, without requiring anything else than an evaluation context.
Ink supports object-oriented design. As we presented it, the basic elements of Ink are types and relations. Roughly, types can be considered as classes, and relations as functions that can be bound to classes.
An abstract expression cannot be evaluated until some information is given to obtain a concrete form of the abstract expression.
For instance, looking back at our Point class, we could have declared the type as follows:
Abstract and concrete expressions
type Point:
annotations are (basic, immutable)
structure is (
x : type Number
y : type Number
)
relations are (
add [p:Point]:
point := Point create
point.x = .x
point.y = .y
[point]
)
For instance, look at the following expression
Here we can notice two things:
1 + 2
- The left member of the relation
addwas omitted - The
.xand.yexpressions have an implicit left member, which a value of the current type.
this is a simple addition, which can be easily computed, here is another form of this expression :
This notation is stricly equivalent to the form we presented above, it is expanded by the Ink compiler in the same way.
a + b
2.1 Data encapsulation
assuming that a = 1 and b = 2, and that both symbols are defined in the evaluation environment, this expression is equivalent to the preceding in this environment, and can be directly evaluated.
One of the basic mechanisms required by object-oriented design is encapsulation. Encapsulation means that direct access to an object internal state is forbidden, and always go through a set of accessors. Accessors are interface between the object internal state and the environment.
Now, let's consider the following pseudo-code :
Accessors are split between accessors and mutators. An accessor allows to access the value of a part of the object state, while a mutator allows to change this value.
f(x,y) = x + y
Here is an example of accessors for the upper-left attribute of the Rectangle type:
we have defined a function which can do the same operation as the two first expressions, provided it is given the proper arguments :
type Rectangle:
structure is (
upper-left: type Point
lower-right: type Point
)
f(1,2)
this form can be evaluated to a concrete expression, which is 1+2. This was made possible because the function f, which is abstract, required two given values to become concrete.
.upper-left access is:
[.upper-left]
.upper-left mutate! <p:Point> is:
.upper-left = p
Consider the following expression
Now, the data structure attributes can be simply accessed:
f(1)
r := Rectangle create r.upper-left = Point create (1, 1) r.lower-right = Point create (2, 2) print r.lower-right.x
this expression cannot be evaluated because it is not concrete: we only know that f(1) = 1 + y, but we still lack information about what value the y symbol is bound to, thus f(1) is still an abstract expression.
--> 2
Abstract expressions in Ink
2.2 Polymorphism
Just as we have shown it in the previous introduction, Ink allows to define abstract expression, not only for function declarations, but also for any other expression.
A second important point of object-orientation is polymorphism.
For instance, the expression
Polymorphism is handled in two different ways in Ink. The first one is by explicit typing: you simply express to which specific types a relation will apply. The other way is by expressing constraints on a value: what structure it should have, which annotations its type should have, and so on.
1 + 2
Polymorphism is then easily realised by specifying constraints on the parameters of a relation. Consider the following examples:
can be abstracted as
[p!:Point] add [p2:Point]: p : (.x, .y) = p2 : (.x, .y)
[a, b]: a + b
[p!:.x Number, .y Number] add [p:.x Number, .y Number] p : (.x, .y) = p2 : (.x, .y)
which can be useful when the expression grows a little bit bigger
[p!] add [p2] p : (.x, .y) = p2 : (.x, .y)
[a, b]: a + b , a + 10 * b
The above declarations seem all similar, but only their process is similar: they apply to different types of values.
abstract expressions, as any other form of expressions can be assigned to slots:
- First expression only applies to
Pointvalues - Second expression applies to any value which as
xandyattributes of typeNumber - Third expression applies to any values which have
xandyattributes.
abstractExpr := [a,b] : a + b
Actually, there is one more constraint for the two last constraints : there must exist a mutator for the x attribute of the left member that accepts the value of the x attribute of the right member, and this is the same for the y attribute.
abstract expression values can then be made less abstract, or conrete by applying arguments to them :
Scoping rules
abstractExpr(1) --> [b] : 1 + b
Design patterns
abstractExpr(1,2) --> 3
Concurrency
You can also choose which arguments you would like to leave abstract, with the following forms :
Application operator and template system
abstractExpr( _, 2 ) --> [a] : a + 2
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
abstractExpr( b = 2 ) --> [a] : a + 2
If we go back to our point addition relation, we see the following block of code:
In the first form we used the _ (underscore) as the explicit declaration for an abstract argument, and specified the value for the second argument. In this case, we explicitely set a as abstract.
point.x = p1.x + p2.x point.y = p1.y + p2.y
In the second form, we used explicit naming to bind to the symbol b of the abstractExpr argument list the value 2. In this case, a was implicitely left as abstract.
Can be rewritten :
(x, y) : <a> point.a = p1.a + p2.a
3. Object model
The application operator is a bit like the shell | operator: you apply the right member of the | to the output of the evaluation of the left member.
Ink supports object-oriented design. As we presented it, the basic elements of Ink are types and relations. Roughly, types can be considered as classes, and relations as functions that can be bound to classes.
Pattern-Matching
For instance, looking back at our Point class, we could have declared the type as follows:
The following examples adds any list that starts with two Number values to the point:
type Point:
annotations are (basic, immutable)
structure is (
x : type Number
y : type Number
)
relations are (
add! [p:Point]:
point := Point create
point.x = .x
point.y = .y
[point]
)
relation [p:Point] add ([x:Number], [y:Number], _ )
Here we can notice two things:
can also be written:
- The left member of the relation
addwas omitted - The
.xand.yexpressions have an implicit left member, which a value of the current type.
relation [p:Point] add ([x,y:Number], _ )
This notation is stricly equivalent to the form we presented above, it is expanded by the Ink compiler in the same way.
Syntax overview
2.1 Data encapsulation
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
One of the basic mechanisms required by object-oriented design is encapsulation. Encapsulation means that direct access to an object internal state is forbidden, and always go through a set of accessors. Accessors are interface between the object internal state and the environment.
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
Accessors are split between accessors and mutators. An accessor allows to access the value of a part of the object state, while a mutator allows to change this value.
Relation naming convention
Here is an example of accessors for the upper-left attribute of the Rectangle type:
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
type Rectangle:
structure is (
upper-left: type Point
lower-right: type Point
)
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
.upper-left access is:
[.upper-left]
.upper-left mutate! <p:Point> is:
.upper-left = p
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
Now, the data structure attributes can be simply accessed:
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
r := Rectangle create r.upper-left = Point create (1, 1) r.lower-right = Point create (2, 2) print r.lower-right.x
Parameters naming convention
--> 2
Formal parameters in relations must be suffixed by ! when the given parameter value is mutated. By default, parameters are immutable, unless they are indicated as mutable by the ! suffix.
2.2 Polymorphism
A second important point of object-orientation is polymorphism.
Polymorphism is handled in two different ways in Ink. The first one is by explicit typing: you simply express to which specific types a relation will apply. The other way is by expressing constraints on a value: what structure it should have, which annotations its type should have, and so on.
Polymorphism is then easily realised by specifying constraints on the parameters of a relation. Consider the following examples:
[p!:Point] add [p2:Point]: p : (.x, .y) = p2 : (.x, .y) [p!:.x Number, .y Number] add [p:.x Number, .y Number] p : (.x, .y) = p2 : (.x, .y) [p!] add [p2] p : (.x, .y) = p2 : (.x, .y)
The above declarations seem all similar, but only their process is similar: they apply to different types of values.
- First expression only applies to
Pointvalues - Second expression applies to any value which as
xandyattributes of typeNumber - Third expression applies to any values which have
xandyattributes.
Actually, there is one more constraint for the two last constraints : there must exist a mutator for the x attribute of the left member that accepts the value of the x attribute of the right member, and this is the same for the y attribute.
Scoping rules
Design patterns
Concurrency
Application operator and template system
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
If we go back to our point addition relation, we see the following block of code:
point.x = p1.x + p2.x point.y = p1.y + p2.y
Can be rewritten :
(x, y) : <a> point.a = p1.a + p2.a
The application operator is a bit like the shell | operator: you apply the right member of the | to the output of the evaluation of the left member.
Pattern-Matching
The following examples adds any list that starts with two Number values to the point:
relation [p:Point] add ([x:Number], [y:Number], _ )
can also be written:
relation [p:Point] add ([x,y:Number], _ )
Syntax overview
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
Relation naming convention
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
Parameters naming convention
Formal parameters in relations must be suffixed by ! when the given parameter value is mutated. By default, parameters are immutable, unless they are indicated as mutable by the ! suffix.
relation <p1:type Point> add <p2:type Point>:
relation [p1:type Point] add [p2:type Point]:
<-- point
[point]
This relation creates a new point which x and y values are the addition of the x and y value of both points. Note that the <-- symbol means return (or yield, as we will see later).
This relation creates a new point which x and y values are the addition of the x and y value of both points. Note that the [point] symbol means return point (or yield point, as we will see later).
directive <p:type Point> clone :
directive [p:type Point] clone :
2. Object model
2. Template system
Ink supports object-oriented design. As we presented it, the basic elements of Ink are types and relations. Roughly, types can be considered as classes, and relations as functions that can be bound to classes.
For instance, looking back at our Point class, we could have declared the type as follows:
3. Object model
Ink supports object-oriented design. As we presented it, the basic elements of Ink are types and relations. Roughly, types can be considered as classes, and relations as functions that can be bound to classes.
For instance, looking back at our Point class, we could have declared the type as follows:
add <p:Point>:
add [p:Point]:
<-- point
[point]
<-- .upper-left
[.upper-left]
<p:Point> add <p2:Point>: p : ( .x, .y ) = p2 : ( .x, .y )
[p!:Point] add [p2:Point]: p : (.x, .y) = p2 : (.x, .y)
<num?=.x type? Number, .y type? Number, p:num?> add <p2 num?> p : ( .x, .y ) = p2 : ( .x, .y )
[p!:.x Number, .y Number] add [p:.x Number, .y Number] p : (.x, .y) = p2 : (.x, .y)
<p> add <p2> p : ( .x, .y ) = p2 : ( .x, .y )
[p!] add [p2] p : (.x, .y) = p2 : (.x, .y)
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
relation [p:Point] add ([x:Number], [y:Number], _ )
relation <p:type? Point> add (<x,y:type? Number>, _ )
relation [p:Point] add ([x,y:Number], _ )
Parameters naming convention
Formal parameters in relations must be suffixed by ! when the given parameter value is mutated. By default, parameters are immutable, unless they are indicated as mutable by the ! suffix.
This relation creates a new point which x and y values are the addition of the x and y value of both points. Note that the <-- symbol means return.
This relation creates a new point which x and y values are the addition of the x and y value of both points. Note that the <-- symbol means return (or yield, as we will see later).
directive <p:type Point> clone! :
directive <p:type Point> clone :
One of the basic mechanisms required by object-oriented design is encapsulation. Enapsulation means that direct access to an object internal state is forbidden, and always go through a set of accessors. Accessors are interface between the object internal state and the environment.
One of the basic mechanisms required by object-oriented design is encapsulation. Encapsulation means that direct access to an object internal state is forbidden, and always go through a set of accessors. Accessors are interface between the object internal state and the environment.
Accessors are split between accessors and mutators. An accessor allows to access the value of a part of the object state, while a mutator allows to change this value.
Accessors are split between accessors and mutators. An accessor allows to access the value of a part of the object state, while a mutator allows to change this value.
Here is an example of accessor with a Rectangle type:
Here is an example of accessors for the upper-left attribute of the Rectangle type:
Polymorphism is handled in two different way in Ink. The first one is by explicit typing: you simply express to which specific types a relation will apply. The other way is by expressing constraints on a value: what structure it should have, which annotations its type should have, and so on.
Polymorphism is handled in two different ways in Ink. The first one is by explicit typing: you simply express to which specific types a relation will apply. The other way is by expressing constraints on a value: what structure it should have, which annotations its type should have, and so on.
Types and relations
1. Types and relations
Object-orientation
2. Object model
Data encapsulation
2.1 Data encapsulation
Polymorphism
2.2 Polymorphism
Polymorphism is handled in two different way in Ink. The first one is by explicit typing: you simply express to which specific types a relation will applw. The other way is by expressing constraints on a value: what structure it should have, which annotations its type should have, and so on.
Polymorphism is handled in two different way in Ink. The first one is by explicit typing: you simply express to which specific types a relation will apply. The other way is by expressing constraints on a value: what structure it should have, which annotations its type should have, and so on.
Polymorphism is then easily realised by specifying constraints to the parameters of a relation. Consider the following examples:
Polymorphism is then easily realised by specifying constraints on the parameters of a relation. Consider the following examples:
The above declaration seem similar, but only their process is similar, but they apply to different values.
The above declarations seem all similar, but only their process is similar: they apply to different types of values.
Scoping rules
Design patterns
Concurrency
Scoping rules
Application operator and template system
Design patterns
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Concurrency
If we go back to our point addition relation, we see the following block of code:
Application operator and template system
point.x = p1.x + p2.x point.y = p1.y + p2.y
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Can be rewritten :
If we go back to our point addition relation, we see the following block of code:
(x, y) : <a> point.a = p1.a + p2.a
point.x = p1.x + p2.x point.y = p1.y + p2.y
The application operator is a bit like the shell | operator: you apply the right member of the | to the output of the evaluation of the left member.
Can be rewritten :
Pattern-Matching
(x, y) : <a> point.a = p1.a + p2.a
The following examples adds any list that starts with two Number values to the point:
Pattern-Matching
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
The following examples adds any list that starts with two Number values to the point:
can also be written: relation <p:type? Point> add (<x,y:type? Number>, _ )
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
Syntax overview
can also be written: relation <p:type? Point> add (<x,y:type? Number>, _ )
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
Syntax overview
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
Relation naming convention
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
Relation naming convention
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
p : ( .x, .y ) = p2 : ( .x, .y )
<p> add <p2> p : ( .x, .y ) = p2 : ( .x, .y )
The above declaration seem similar, but only their process is similar, but they apply to different values.
- First expression only applies to
Pointvalues - Second expression applies to any value which as
xandyattributes of typeNumber - Third expression applies to any values which have
xandyattributes.
Scoping rules
Actually, there is one more constraint for the two last constraints : there must exist a mutator for the x attribute of the left member that accepts the value of the x attribute of the right member, and this is the same for the y attribute.
Design patterns
Concurrency
Application operator and template system
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Scoping rules
If we go back to our point addition relation, we see the following block of code:
Design patterns
point.x = p1.x + p2.x point.y = p1.y + p2.y
Concurrency
Can be rewritten :
Application operator and template system
(x, y) : <a> point.a = p1.a + p2.a
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Pattern-Matching
If we go back to our point addition relation, we see the following block of code:
The following examples adds any list that starts with two Number values to the point:
point.x = p1.x + p2.x point.y = p1.y + p2.y
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
Can be rewritten :
can also be written: relation <p:type? Point> add (<x,y:type? Number>, _ )
(x, y) : <a> point.a = p1.a + p2.a
Syntax overview
Pattern-Matching
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
The following examples adds any list that starts with two Number values to the point:
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
Relation naming convention
can also be written: relation <p:type? Point> add (<x,y:type? Number>, _ )
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
Syntax overview
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
Relation naming convention
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
point := Point create!
point := Point create
You can also note that there is something that looks like an invocation: Point create!. In fact, the create! symbol denotes a directive, which is a specific kind of relation. In our case, the create! directive is a primitive directive, which is note declared in Ink.
You can also note that there is something that looks like an invocation: Point create. In fact, the create symbol denotes a directive, which is a specific kind of relation. In our case, the create directive is a primitive directive, which is note declared in Ink.
clone := Point create!
clone := Point create
point := Point create!
point := Point create
.upper-left access! is:
.upper-left access is:
Now, the data structure attributes can be simply accessed:
r := Rectangle create r.upper-left = Point create (1, 1) r.lower-right = Point create (2, 2) print r.lower-right.x
Scoping rules
--> 2
Design patterns
Polymorphism
Concurrency
A second important point of object-orientation is polymorphism.
Application operator and template system
Polymorphism is handled in two different way in Ink. The first one is by explicit typing: you simply express to which specific types a relation will applw. The other way is by expressing constraints on a value: what structure it should have, which annotations its type should have, and so on.
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Polymorphism is then easily realised by specifying constraints to the parameters of a relation. Consider the following examples:
If we go back to our point addition relation, we see the following block of code:
<p:Point> add <p2:Point>: p : ( .x, .y ) = p2 : ( .x, .y )
point.x = p1.x + p2.x point.y = p1.y + p2.y
<num?=.x type? Number, .y type? Number, p:num?> add <p2 num?>
Can be rewritten :
(x, y) : <a> point.a = p1.a + p2.a
Pattern-Matching
The following examples adds any list that starts with two Number values to the point:
Scoping rules
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
Design patterns
can also be written: relation <p:type? Point> add (<x,y:type? Number>, _ )
Concurrency
Syntax overview
Application operator and template system
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
If we go back to our point addition relation, we see the following block of code:
Relation naming convention
point.x = p1.x + p2.x point.y = p1.y + p2.y
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
Can be rewritten :
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
(x, y) : <a> point.a = p1.a + p2.a
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
Pattern-Matching
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
The following examples adds any list that starts with two Number values to the point:
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
can also be written: relation <p:type? Point> add (<x,y:type? Number>, _ )
Syntax overview
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
Relation naming convention
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
Scoping rules
Data encapsulation
Design patterns
One of the basic mechanisms required by object-oriented design is encapsulation. Enapsulation means that direct access to an object internal state is forbidden, and always go through a set of accessors. Accessors are interface between the object internal state and the environment.
Concurrency
Accessors are split between accessors and mutators. An accessor allows to access the value of a part of the object state, while a mutator allows to change this value.
Application operator and template system
Here is an example of accessor with a Rectangle type:
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
type Rectangle:
structure is (
upper-left: type Point
lower-right: type Point
)
If we go back to our point addition relation, we see the following block of code:
.upper-left access! is:
<-- .upper-left
.upper-left mutate! <p:Point> is:
.upper-left = p
point.x = p1.x + p2.x point.y = p1.y + p2.y
Can be rewritten :
(x, y) : <a> point.a = p1.a + p2.a
Scoping rules
Pattern-Matching
Design patterns
The following examples adds any list that starts with two Number values to the point:
Concurrency
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
Application operator and template system
can also be written: relation <p:type? Point> add (<x,y:type? Number>, _ )
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Syntax overview
If we go back to our point addition relation, we see the following block of code:
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
point.x = p1.x + p2.x point.y = p1.y + p2.y
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
Can be rewritten :
(x, y) : <a> point.a = p1.a + p2.a
Pattern-Matching
The following examples adds any list that starts with two Number values to the point:
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
can also be written: relation <p:type? Point> add (<x,y:type? Number>, _ )
Syntax overview
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
Relation naming convention
When a relation does not have any side effect (it is purely functional), it does not need any suffix.
If the relation has a side effects, i.e. it mutates one of the relation members, it must be suffixed by !.
If the relation is a predicate, i.e. it is purely functional and returns a Boolean value, it must be suffixed with ?.
This convention, inspired from Scheme, allow to clearly identify whether invoking a relation will have a side effect or not.
return point
<-- point
This relation creates a new point which x and y values are the addition of the x and y value of both points.
This relation creates a new point which x and y values are the addition of the x and y value of both points. Note that the <-- symbol means return.
relations:
relations are (
return point
<-- point )
Scoping rules
Ink syntax was designed to be both clear and flexible, trying to limit the possible ambiguities, trying to enforce the code source presentation to be the most coherent. Ink source code tries to be explicit, clear and clearly differentiate the important structural and semantic elements.
Application operator and template system
Object-orientation
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Ink supports object-oriented design. As we presented it, the basic elements of Ink are types and relations. Roughly, types can be considered as classes, and relations as functions that can be bound to classes.
If we go back to our point addition relation, we see the following block of code:
For instance, looking back at our Point class, we could have declared the type as follows:
point.x = p1.x + p2.x point.y = p1.y + p2.y
type Point:
annotations are (basic, immutable)
structure is (
x : type Number
y : type Number
)
relations:
add <p:Point>:
point := Point create!
point.x = .x
point.y = .y
return point
Can be rewritteng :
Here we can notice two things:
(x, y) : <a> point.a = p1.a + p2.a
- The left member of the relation
addwas omitted - The
.xand.yexpressions have an implicit left member, which a value of the current type.
Syntax overview
This notation is stricly equivalent to the form we presented above, it is expanded by the Ink compiler in the same way.
Design patterns
Concurrency
Application operator and template system
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
If we go back to our point addition relation, we see the following block of code:
point.x = p1.x + p2.x point.y = p1.y + p2.y
Can be rewritten :
(x, y) : <a> point.a = p1.a + p2.a
Pattern-Matching
The following examples adds any list that starts with two Number values to the point:
relation <p:type? Point> add ( <x:type? Number>, <y:type? Number>, _ )
can also be written: relation <p:type? Point> add (<x,y:type? Number>, _ )
Syntax overview
Application operator and template system
You can also note that there is something that looks like an invocation: Point create!. In fact, the create! symbol denotes a directive, which is a specific kind of relation. In our case, the create! directive is a primitive directive, which is note declared in Ink.
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
Here is an example of directive which creates a clone of a point:
If we go back to our point addition relation, we see the following block of code:
directive <p:type Point> clone! : clone := Point create! clone.x = p.x clone.y = p.y return clone
point.x = p1.x + p2.x point.y = p1.y + p2.y
Application operator and template system
Can be rewritteng :
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
(x, y) : <a> point.a = p1.a + p2.a
If we go back to our point addition relation, we see the following block of code:
Syntax overview
point.x = p1.x + p2.x point.y = p1.y + p2.y
Can be rewritteng :
(x, y) : <a> point.a = p1.a + p2.a
Syntax overview
We see here that the type point is declared with the basic and immutable annotations, and that it declares its data structure to be composed of Numbers names x and y.
We see here that the type point is declared with the basic and immutable annotations, and that it declares its data structure to be composed of Numbers names x and y.
Relations are processes that are bound to two values (a value is an instance of type), they are pretty much like (if not equivalent to) generic functions.
For instance, here is a relation related to the Point type:
relation <p1:type Point> add <p2:type Point>: point := Point create! point.x = p1.x + p2.x point.y = p1.y + p2.y return point
This relation creates a new point which x and y values are the addition of the x and y value of both points.
Application operator and template system
One of the most important Ink idiom the application operator :. It is the basic way of expressing the program structure.
If we go back to our point addition relation, we see the following block of code:
point.x = p1.x + p2.x point.y = p1.y + p2.y
Can be rewritteng :
(x, y) : <a> point.a = p1.a + p2.a
Syntax overview
Before getting into the depths of Ink, it would be good to have a slight overview of its syntax. Ink syntax shares some common points with Python, Io, Haskell and... ahem... C++ (just for templates, as you will see).
Describe {{Ink}} here.
The Ink Programming Language
Ink is a relation-based programming language. It is a based on a clear separation between data and processes, is reflective, offers choice between static or dynamic typing, features ddesign by contract and time-constraint programming.
Types and relations
Types and relations are the core concepts of Ink. A type is the formalisation of a data model, which consists in a composition of primitive elements (numbers, strings, lists, etc), which can be annotated with attributes.
For instance, Ink defines the Point type as follows:
type Point:
annotations are (basic, immutable)
structure is (
x : type Number
y : type Number
)
We see here that the type point is declared with the basic and immutable annotations, and that it declares its data structure to be composed of Numbers names x and y.
