-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A New Design for Tuples in Rascal #154
Comments
Cool stuff. Lets talk about tuple equality. When are they equal and when I would prefer that tuples that do not have a given keyword parameter to be tuple[int w=0, int h = 0] t = <h=1>; The tuple literal does not know or need to be aware of the fact that it tuple[int w=0, int h = 0] u = <h=1, w=0>; u == t should be true even though the runtime tuple type of t does not see A solution would be to store the value of u the same as t, namely without This came out of a discussion with Nastya. On Friday, March 1, 2013, Paul Klint wrote:
Jurgen Vinju
|
I think variadic argument lists are most useful in languages that do not On Friday, March 1, 2013, Paul Klint wrote:
Jurgen Vinju
|
Is row polymorphism only for the nonpositional fields? Otherwise i could On Friday, March 1, 2013, Paul Klint wrote:
Jurgen Vinju
|
Row polymorphism works both for positional and keyword fields. This is illustrated by the example Tuple matching. In
the success of the match is determined by a positional field ( |
I agree with the treatement of equality as @jurgenvinju proposes. It differs from how this is done in the current implementation of default values (the default case is also stored in the runtime value). |
Ok that looks good. I am worried about field projection from a relation On Saturday, March 2, 2013, Paul Klint wrote:
Jurgen Vinju
|
Can you be more precise? The phrase "a relation where not all tuples have all fields" is unclear. In the tuples as proposed:
It may be that you are just worrying about implementation details. Given
then |
Yes, only details that i am worried abput. On Saturday, March 2, 2013, Paul Klint wrote:
Jurgen Vinju
|
Looks good! I'm a bit confused on when a field is positional or not. Is a field a keyword field (i.e. not positional) if it has a default value? If so, the fact that a field has a default value is part of the type? Or is the default value itself part of the type. If so are two types with the same fields but different default values equalivalent or not? Also, i am in favour of removing varargs, it's just too messy :) |
I propose we make the default values part of the type (they have to be), but do not include them in type equality, that is two tuple types are the same if they have the same keyword arguments, with the same types, but their default values may be different. This then allows us to have multiple aliases for the same type with different default values. |
@atzeus that was my first thought to, but that it not going to be modular and representations will differ at run-time, so sharing is impossible to get fast. They should be part of static types, but not of dynamic run-time types in order to allow transparent substitution if the values are equal. Multiple aliases for the same type with different default values is already possible without this BTW. The static type system decides which default value to produce based on the receiver type. The run-time then checks whether the value has the keyword parameter or not. If it does, it projects this value from the tuple, if not the expression has been annotated by the type checker with necessary default value. |
One remark (unfortunately, not inline): tuple concatenation should work as map concat: values of keyword params in right-hand side override the values of the keyword args in the left if there overlapping keys. |
Would it be possible to extend tuple types with keyword params later? E.g. given
And then in another module:
Maybe a bit weird using |
I think that works out of the box due to shadowing and subtyping. On Monday, March 4, 2013, Tijs van der Storm wrote:
Jurgen Vinju
|
@atzeus yes a field (or parameter) is a keyword field/parameter since it has a default value and that default value is part of the type. @jurgenvinju / @tvdstorm I am not yet completely sure how this aliasing business will work out but let's be optimistic. @tvdstorm you are right about tuple concatenation. |
Further Analysis of Proposed Tuple Types_Anastasia Izmaylova, Paul Klint_ AbstractIn “A new Design for Tuples in Rascal” (see #154) we have proposed extensions to Rascal tuples. This design aims at (1) combining conventional tuples and extensible records, and (2) unifying concepts of tuples and function/constructor signatures with keyword parameters, which will enable more concise and extensible code. Here we discuss some implications for static and dynamic semantics. First, we outline our design, and then we give concrete examples to demonstrate the design and some implications. Outline of the designThe basic idea of the extension is to allow additional fields in tuple types and tuple values in the style of keyword parameters. We call them _keyword fields_. Thus, we enrich tuple semantics with
Summary of design constraintsThere are a number of global design constraints:
Discussion on tuple types and equality of tuple values
Tuple typesWe consider here the design alternative: default values are represented in the static type of a tuple. We make a distinction between
In the following we give simple running examples. To avoid notational clutter in this exploratory phase, we use:
Note that we temporarily separate positional elements and keyword fields with a LUB (least upper bound)The following are true for our running examples:
SubtypingThe intuition behind subtyping is that the smaller type corresponds with a “smaller” set (subset) of values (in an informal sense, the value sets may be infinite). This gives the following ordering:
_Note_ that subtyping under the latter two bullets defines substitutability when the expression of a type with less keyword fields may be used in place where a type with more keyword fields _with_ default values is required. From this, the following is also true: Associating a type with a tuple expressionWhen associating a type with a tuple expression, we have to rely on local information; hence, we are limited in what we can infer:
AssignmentThe design alternative we discuss is to associate with each value Examples:
We expect that: Implications for assignment
It might look weird for some cases, reasonable for others, and unavoidable for the rest, e.g.,
The above _does_ look reasonable and useful.
( The above _does_ look unintuitive, but, on the other hand, it is type-safe and Compare the latter with:
Another example of such behaviour:
Also,
The above _is_ unavoidable - there are some ignorable attributes possible, but we do not know anything about them. One final example:
To summarize: it makes sense to ignore keyword fields with default values in subtyping, which does not lead to unsoundness as runtime behavior depends on the full extra static information, e.g., EqualityEquality follows the way values are represented: values are equal (==) when
Two tuple values are _always equal_ when either (1) their actual runtime values are identical, or (2) when they are not identical, but they would have become identical after inserting default values according to their respective static types. Here are some representative examples for
MatchingWe discuss matching also by some representative examples. There are a number of issues to resolve:
Examples:
Type Type
Result: Discussion: this example illustrates _Issue 1_ mentioned above. There are two designs possible here: (1) as above, where unmatched keyword fields in the subject do not affect the match, or (2) require always a full structural match, like In the following examples we assume the first choice.
Type Type
Result:
Type Type
New notation: Type Type
Result:
Type Type
Result:
Type Type
Result:
Type Type
Result: Discussion: this example illustrates _Issue 2_ mentioned above. The subtype relation has to be adapted to take care of We do this here by examples:
is true for
is true for
Type Type
Result:
Type Type
Type Type
Result: Splicing and overridingSince we use overriding in cases of keyword fields with the same name, we get:
A similar example:
with the same outcome:
Other examples:Example 1: Given:
we get:
Example 2: Given:
we get:
is perfectly ok, since the type of the element value Example 3: Given:
then we have Example 4: Here is a description of the
An alternative -- and probably more consistent -- design is to represent all parameters (
|
A New Design for Tuples in Rascal
Current Design
The current tuple type is defined by the type constructor tuple with a list of ordered (optionally named) fields:
tuple[t1 n1, t2 n2, … ].
An example is the type
tuple[str name, int age]
. The assignmentB = <”Belle”, 3>
assigns a tuple of this type to variableB
.The elements of a tuple can be accessed by
B[0]
.B.name
(provided that the fieldname
is present)The following operations are available for tuples:
+
operator.Problems to be addressed
Proposed Design
The proposed design can be summarized as: “add unordered keyword fields with default value to tuples and introduce tuple splicing”. More precisely, the arguments of the tuple constructor may be (in this order):
The elements of a tuple value can be accessed as follows:
The following operations are available on these enhanced tuples:
For completeness sake, we may want support tuple substraction as well.
Some examples
Introduce CourseGrade to represent the grades for a course:
Create a CourseGrade value:
CourseGrade g = <“algebra II”, [4, 5, 7], obligatory = false>;
Define a function that computes average grades:
Tuple concatenation:
Tuple splicing:
Assume
A = <[4, 5, 7], prerequisites = true>
, thenTuple Matching:
The match
will succeed and creates the bindings:
name == “algebra II”
,O == true
,R = <[4,5,7], prerequisites= true>
Tuple Matching
We make the concept of tuple matching now a bit more precise. A tuple pattern
P
and a tuple valueT
, match iffP
contains no multi-variable:*Unmatched postional fields and keyword fields are collected in a tuple that is bound to the multi-variable.
The following example matches will succeed:
<3, 4, b=true> := <3, 4, x=3.5, b=true>
<3, *R> := <3, 4, x=3.5, b=true>
andR
will be bound to<4, x=3.5, b=true>
<b=true, *R> := <3, 4, x=3.5, b=true>
andR
will be bound to<3, 4, x=3.5>
Function calls
Disregarding varyadic arguments (see the discussion below), function signatures and tuples are identical in the proposed design. Both consist of an ordered list of positional parameters followed by an unordered list of keyword parameters/fields. Consider the following function:
It can easily be rewritten as:
The only inconvenience is that we have to prefix every use of a field with “s.” To solve this, we want tuple splicing at the level of argument lists (which is completely natural if we consider the argument list as a tuple). For instance,
The function
scale3
can be called in two ways:x1 = scale3(3.5, factor=3);
Scale s = <3.5, factor=3); x1 = scale3(s);
Now suppose the arguments of a function are coming both from direct arguments of the function and from arguments coming from a tuple argument. Then we have to concatenate the direct arguments and the spliced-in tuple arguments as follows:
Typical calls to
scale4
are:x1 = scale4(3.5, printit=true, factor=3);
Scale s = <3.5, factor=3); x1 = scale4(printit=true, s);
Examples
Domain
The domain function for relations of any arity looks like this:
Range
The range function for relations of any arity looks like this:
Observe that the precise type of the range is returned, e.g.,
Compose
The composition of two relations (both of arity of at least 2) could be defined as:
Note that this is an interesting example since the result type contains two multi-variables.
Move (using a positional field)
Define a move function that is applicable to any tuple that has a first field x and returns a new tuple with x incremented by 1. An example of such a tuple type is:
Move (using a keyword field)
Define a move function that is applicable to any tuple that has a keyword field x, such as in:
Davy’s Example
This example (see #94) is about passing keyword parameters to a recursive call of the same function. The solution is to use tuple splicing in the function signature.
Tijs’ Example
This is similar to Davy’s example in a slightly different setting:
Grammar of Graphics
The Grammar of Graphics is way of organizing data to gradually transform input data into a format that makes it simple to draw charts. Essentially, given relations are extended with auxiliary columns to represent the drawing information. Here is an example function
geoms
that takes a dataset as input and extends it with a fieldgeom
that indicates whether a circle or square should be drawn at each position (described by the required keyword fieldsx
andy
):Definition and Implementation
PDB
The following changes to the PDB are needed:
Note: a more general issue is where to store this information (in the type or in the value). The implementation of keyword parameters/fields should be uniform for nodes, constructors and tuples.
Syntax for tuple type
The current definition of tuple type is:
The new definition will be:
Notes:
Rascal Interpreter
This will affect the following parts of the Rascal interpreter:
Other Tools
Staging of Implementation
Remaining Issues
Varyadic arguments for functions
In principle, one could add varyadic fields to tuples as well (using the same notation as we have for varyadic function arguments) but this makes it hard to infer the tuple type. For instance, consider
<”abc”, 1, 2, 3>
is its type:tuple[str,int,int,int]
, or rathertuple[str, int …]
, or rathertuple[str, list[int]]
.To avoid this confusion, we have not added varyadic field to tuples.
But how about functions with varyadic arguments? There are two solution directions:
The prototypical example of varyadic arguments is a print function:
void print(value v …) { … }
With a call like:
print(1, “bc”, false);
If we remove varyadic arguments then the following alternatives are available to define the print function:
void print(list[value] vals) { … };
Call:print([1, “bc”, false]);
void print([*value vals]) { … } ;
Call:print([1, “bc”, false]);
void print(*tuple[*&X] vals){ … };
Call:print(1, “bc”, false);
In the first two styles, vals is bound to a list of values, in the last one, to a tuple of value fields.
The text was updated successfully, but these errors were encountered: