64
64
65
65
The translator will see a generic function definition like this:
66
66
67
- generic function f(a, b, ...rest);
67
+ generic function f(a:int , b, c=10 , ...rest);
68
68
69
69
and will turn it into something like this:
70
70
71
- var f = new GenericFunction(2 , true);
71
+ var f = new GenericFunction([int,AnyType,AnyType], [,,10] , true);
72
72
73
73
Then methods scattered throughout the program, like these:
74
74
75
- generic function f(a: int, b: boolean, ...rest) {
75
+ generic function f(a: int, b: boolean, c: Numeric, ...rest) {
76
76
return a+b
77
77
}
78
78
79
79
are turned into calls to addMethod:
80
80
81
- f.addMethod([int, boolean], function (nextMethod, a:int, b:boolean, ...rest) { return a+b })
81
+ f.addMethod([int, boolean, Numeric],
82
+ function (nextMethod, a:int, b:boolean, c:Numeric, ...rest) { return a+b })
82
83
83
- Generally very few errors are signalled when a method is added,
84
- most of the interesting work happens when f is called.
84
+ Generally few errors are signalled when a method is added, most of
85
+ the interesting work happens when f is called.
85
86
86
87
Note that the translator must translate the annotations '*' into
87
88
AnyType, 'null' into NullType, and 'undefined' into UndefinedType.
122
123
if any, followed by the list of implemented interfaces in order,
123
124
if any. This seems reasonable but there may or may not be a
124
125
more reasonable approach for ECMAScript, as that is modelled on
125
- a multiple-inheritance language.
126
+ a multiple-inheritance language. MultiJava may offer insight.
127
+
128
+ (7) GenericFunction subclasses Object instead of Function because the
129
+ meta invoke() method of the latter is final. I don't know why
130
+ it should be, really; it would be reasonable for GenericFunction
131
+ to subclass Function.
126
132
*/
127
133
128
134
package
@@ -135,32 +141,54 @@ package
135
141
136
142
public class GenericFunction extends Object
137
143
{
138
- function GenericFunction (required : uint , more : boolean )
139
- : required = required
144
+ function GenericFunction (constraints :Array , defaults :Array , more : boolean )
145
+ : required = constraints .length
146
+ , constraints = constraints
147
+ , defaults = defaults
140
148
, more = more
141
149
{
142
150
}
143
151
144
152
public function addMethod (specializers : Array , body : function ()) {
145
153
if (specializers .length != required )
146
154
throw "Generic function requires exactly " + required + " specializers" ;
155
+
156
+ for ( let i =0 , limit =specializers .length ; i < limit ; i ++ )
157
+ if (!isSubtype (specializers [i ], constraints [i ]))
158
+ throw "Specializer fails subtype check" ;
159
+
160
+ for ( let i =0 , limit =methods .length ; i < limit ; i ++ ) {
161
+ let thesame = true ;
162
+ let m_specializers = methods [i ].specializers ;
163
+ for ( let j =0 , limit =specializers .length ; thesame && j < limit ; j ++ )
164
+ if (specializers [j ] !== m_specializers [j ])
165
+ thesame = false ;
166
+ if (thesame )
167
+ throw "Generic method redefinition is not allowed." ;
168
+ }
169
+
147
170
methods .push ({specializers : specializers , body : body });
148
171
}
149
172
150
173
meta final function invoke (...args ) {
151
- checkCongruence (args . length );
174
+ checkCongruence (args );
152
175
153
176
let types = computeManifestTypes (args );
154
177
let [applicable , uncomparable ] = sortMethods (selectApplicableMethods (methods , types ), types );
155
178
156
179
return callMethodsInOrder (applicable , args );
157
180
}
158
181
159
- function checkCongruence (nactuals ) {
160
- if (nactuals < required )
161
- throw new TypeError ("Not enough arguments to generic function" );
182
+ function checkCongruence (args ) {
183
+ let nactuals = args .length ;
162
184
if (nactuals > required && !more )
163
185
throw new TypeError ("Too many arguments to generic function" );
186
+ if (nactuals < required ) {
187
+ if (defaults == null || !defaults .hasOwnProperty (nactuals ))
188
+ throw new TypeError ("Not enough arguments to generic function" );
189
+ for ( let i =nactuals ; i < required ; i ++ )
190
+ args [i ] = defaults [i ];
191
+ }
164
192
}
165
193
166
194
function computeManifestTypes (args ) {
@@ -267,6 +295,8 @@ package
267
295
}
268
296
269
297
var required ;
298
+ var defaults ;
299
+ var constraints ;
270
300
var more ;
271
301
const methods = new Array ;
272
302
}
@@ -383,7 +413,7 @@ package
383
413
* System hooks -- a sketch for meta-objects functionality.
384
414
*/
385
415
386
- function typeOf (v ) {
416
+ public function typeOf (v ) {
387
417
switch type (v ) {
388
418
case (v :undefined ) { return UndefinedType }
389
419
case (v :null ) { return NullType }
@@ -480,6 +510,7 @@ package
480
510
if (x == int ) return "int" ;
481
511
if (x == double ) return "double" ;
482
512
if (x == AnyType ) return "*" ;
513
+ if (x == Number ) return "Number" ;
483
514
return "???" ;
484
515
}
485
516
0 commit comments