git @ Cat's Eye Technologies Unlikely / b136aeb
Mercurial is no longer supported here. Rename `*.markdown` to `*.md`. Chris Pressey 1 year, 5 months ago
7 changed file(s) with 535 addition(s) and 541 deletion(s). Raw diff Collapse all Expand all
+0
-3
.hgignore less more
0 syntax: glob
1
2 *.pyc
+0
-3
.hgtags less more
0 a755dc2d82a3e7e51bf27f142d0f90d20fe0ea12 rel_1_0_2012_0316
1 fccf574a353121cc19650c06bac75d81bcf05dec rel_1_0_2013_1014
2 d1e706f743d97cc00e2f150ce2bae32a531f1c70 rel_1_0_2014_0819
+0
-489
README.markdown less more
0 The Unlikely Programming Language
1 =================================
2
3 Overview
4 --------
5
6 Unlikely is a programming language with the following traits:
7
8 - Unlikely conflates objects with continuations, and methods with
9 labels. All classes are subclasses of the root class `Continuation`.
10 Every object can be continued at any method. Every method, except
11 for the `continue` method on the built-in class `Stop`, must
12 continue some other method at the end of its definition.
13 - All Unlikely program structures are exposed as objects with
14 commensurate inheritance relationships. For example, every Unlikely
15 program is a subclass of `Program`, and the classes `If` and
16 `Switch` are both subclasses of the abstract base class `Branch`.
17 - Unlikely takes dependency injection to the logical extreme.
18 Dependency injection is an increasingly popular modern
19 object-oriented program construction technique which allows the
20 specific classes which will be used by some class ("dependencies")
21 to be specified ("injected") when that class is instantiated.
22 Unlikely goes one step further by *requiring* that all specific
23 classes used by some class are specified during instantiation.
24
25 Semantics
26 ---------
27
28 ### Classes
29
30 A class is a schema describing a set of objects. Instantiating a class
31 produces a new object of that class. When a class is instantiated, all
32 classes that are referenced by the class (dependant classes) must be
33 named (injected) by the instantiating code (the instantiator). For each
34 requested dependant class, any subclass of it may be supplied by the
35 instantiator, further specifying and constraining behaviour (a technique
36 called dependency injection). In this way, classes are inherently
37 parameterized.
38
39 When a class refers to itself, it is considered a dependant class of
40 itself; it (or a subclass) must be injected by the instantiator.
41
42 All specified dependant classes must be unique (no dependant class may
43 be specified more than once.) Final classes need not and may not be
44 specified as dependant classes because, being final, there is no
45 subclass that the instantiator could possibly substitute for them.
46
47 Each class may define zero or more properties and zero or more methods.
48
49 #### Inheritance
50
51 Whenever a class is defined in Unlikely source code, a superclass must
52 be named; the class being defined is thus a subclass that inherits from
53 that superclass. Its inheritance consists of the properties and methods
54 defined by the superclass and all of its ancestors (i.e. including all
55 properties and methods that the superclass inherited from its own
56 superclasses) as well as the dependant classes of the superclass. The
57 subclass may not inject dependencies when inheriting from a superclass.
58 Only single inheritance is supported.
59
60 A subclass may override methods that it inherits from its superclass. It
61 may access the method definition of its direct superclass (or any
62 indirect ancestor class) by naming that superclass explicitly in a
63 continue.
64
65 A class may be declared as final, in which case it may not be
66 subclassed. In addition, final dependant classes may not be injected.
67
68 A class may also be declared as saturated, in which case it can be
69 subclassed, but subclasses of it must also be declared as saturated, and
70 they cannot define any new methods. They can only override existing
71 methods. In fact, the root class `Continuation` is declared saturated,
72 so really, all objects have exactly one method, `continue`.
73
74 If a class defines or inherits any abstract methods, that class must be
75 declared as abstract. Abstract classes cannot be instantiated. Any
76 subclass of an abstract class must define all inherited abstract methods
77 in order to be considered concrete and thus instantiatable.
78
79 ### Properties
80
81 Each property has a particular type, which is a class. The values it may
82 take on are objects of that class, or of its subclasses.
83
84 Each object has its own instances of the properties defined on the
85 class, and each of these properties may take on different values.
86
87 All state of an object is stored in its properties. Properties are
88 effectively public; they can be modified by code in any method in any
89 class.
90
91 The root class `Continuation` defines one property, `accumulator`, of
92 type `Passive`, which all classes inherit.
93
94 Subclasses may not override inherited properties.
95
96 ### Methods
97
98 A method is a label on a piece of code inside a class. The methods of a
99 class are shared by all objects of that class.
100
101 A method may be declared abstract instead of defining code for it.
102 Classes which contain abstract methods must themselves be declared
103 abstract.
104
105 Only one thing may be done to a method in code, which is to continue it
106 with respect to some object; this is described in the next section.
107
108 A method may declare zero or more arguments. Each argument has a type,
109 which is a class. When a method is continued, a value of the
110 corresponding type (or some subclass of that type) must be given for
111 each argument. In actuality, the arguments merely name properties of the
112 object; they must already be declared in the class before they are
113 listed in the declaration of the method. Passing values in arguments is
114 just shorthand for assigning these properties before continuing the
115 method.
116
117 Methods do not have local variables, so for storage must use the
118 properties of the object on which they were continued.
119
120 The root class `Continuation` defines one abstract method which
121 subclasses must implement, called `continue(Passive accumulator)`. By
122 convention, this method is what other methods continue. The accumulator
123 is passed from continuation to continuation, manipulated as execution
124 proceeds.
125
126 ### Code
127
128 The code inside a class labelled by a method consists of a series of
129 assignments followed by a continue.
130
131 Each assignment consists of an object property on the left-hand side,
132 and an expression on the right-hand side. The the property so named will
133 take on the value resulting from evalulating the given expression.
134 Expressions consist of instantiations of new objects, and references to
135 other object properties.
136
137 The continue names a method on an object to which control flow will
138 immediately pass. It may also pass values as arguments to that method;
139 however, this is mere shorthand for assigning properties of the object
140 on which the method being continued is defined. See above under
141 "Methods" for more details.
142
143 ### Passive Data
144
145 Passive data values, such as integers and strings, are modelled somewhat
146 specially in Unlikely, in order to strike a balance in language design
147 between "too straightforward" and "too convoluted".
148
149 All passive data values are instances of some subclass of the abstract
150 class `Passive`, which is itself a subclass of `Chain`. When a passive
151 data value is continued, it passes its own value into the accumulator of
152 the "next" continuation. (It is not necessary, however, to continue the
153 passive data value to obtain its value in all cases.)
154
155 Each immediate subclass of `Passive` gives a data type of values, such
156 as `Integer` or `String`. Each of these type-classes has a countably
157 infinite number of subclasses, one for each possible value of that type.
158 It is these classes that are instantiated to acquire a passive value
159 object. For example, `three = new 3()` instantiates the value 3. When
160 the `continue` method on this object is continued, the value that it
161 represents will be passed down the chain to the continuation assigned to
162 its `next` property. For example, `three.next = new Print()` would cause
163 3 to be printed when `three` was continued.
164
165 None of the direct subclasses of `Passive` can be further subclassed. In
166 effect, they are final (despite being abstract!) because all possible
167 subclasses of them already exist.
168
169 Syntax
170 ------
171
172 ### Overview
173
174 The overall schema of a class definition is:
175
176 class ClassName(ClassName,ClassName) extends ClassName {
177 ClassName propname;
178 method methodname(ClassName propname, ClassName argname) {
179 propname = new ClassName(ClassName,ClassName);
180 propname.propertyname = argname;
181 goto expr.methodname(expr,expr);
182 }
183 }
184
185 ### Grammar
186
187 A somewhat more formal definition of the syntactic structure of Unlikely
188 code is given in the following EBNF-like grammar.
189
190 ClassBase ::= {ClassDefn}.
191 ClassDefn ::= "class" ClassName<NEW> "(" [ClassName {"," ClassName}] ")" "extends" ClassName
192 ["{" {PropDefn} {MethodDefn} "}"] ["is" ClassMod {"and" ClassMod}].
193 ClassMod ::= "final" | "saturated" | "abstract".
194 PropDefn ::= ClassName PropName<NEW> ";".
195 MethodDefn ::= "method" MethodName<NEW> "(" [ParamDecl {"," ParamDecl}] ")"
196 ("{" {Assignment} Continue "}" | "is" "abstract").
197 ParamDecl ::= ClassName PropName.
198 Assignment ::= QualName "=" Expr ";".
199 Continue ::= "goto" PropName "." MethodName "(" [Expr {"," Expr}] ")" ";".
200 Expr ::= ConstrExpr | QualName.
201 ConstrExpr ::= "new" (ClassName | Constant) "(" [ClassName {"," ClassName}] ")".
202 QualName ::= PropName {"." PropName}.
203 ClassName ::= <<sequence of alphabetic characters>> | Constant.
204 Constant ::= <<sequence of decimal digits>> | <<sequence of arbitrary characters between double quotes>>.
205
206 Note that multiple ClassDefns for a single class may appear; each may
207 partially define the class. In this way a "forward declaration" of a
208 class may occur. This may give its name, superclass, and dependant
209 classes, so these can be consumed by some following class that requires
210 them, before the methods of this class are defined. The dependant
211 classes are cumulative over successive partial definitions; they need
212 not be repeated. However the same superclass must be specified for all
213 partial definitions of a class.
214
215 Built-in Classes
216 ----------------
217
218 - `Continuation`
219
220 The abstract base class that is the superclass of all Unlikely
221 classes, and which can't be instantiated. Declares the property
222 `Passive accumulator`, and the abstract method
223 `continue(Passive accumulator)`, which all concrete subclasses must
224 implement. Is declared `saturated`, so no subclass may declare or
225 define any additional methods.
226
227 - `Program`
228
229 An abstract continuation that provides the guarantee that it can
230 be started (that is, that its `continue` method can be initially
231 continued) from the operating system. It can be reasonably
232 expected that the `accumulator` will be assigned a value
233 provided by the user, perhaps via a command-line argument.
234
235 - `Stop`
236
237 A concrete continuation which exits to the operating system
238 when continued. The accumulator is used as the exit code,
239 assuming the operating system supports this.
240
241 - `Chain`
242
243 An abstract continuation which defines the property
244 `Continuation next`. When a subclass of `Chain` is
245 continued, it will generally continue the continuation
246 assigned to its `next` property after doing something.
247
248 - `Passive`
249
250 The abstract final base class representing passive data
251 values. Discards whatever accumulator was passed to it,
252 and passes its own value into the accumulator when it
253 continues the continuation assigned to its `next`
254 property.
255
256 - `Boolean`
257
258 The abstract final base class representing boolean
259 values.
260
261 - `True`, `False`
262
263 Final classes representing particular boolean
264 values.
265
266 - `Integer`
267
268 The abstract final base class representing integer
269 values.
270
271 - `0`, `1`, `2`...
272
273 Final classes representing particular integer
274 values. Note that only positive constants are
275 available; negative values must be computed by
276 subtracting from 0.
277
278 - `String`
279
280 The abstract final class representing string values.
281
282 - `""`, `"a"`, `"b"`, `"aa"`...
283
284 Final classes representing particular string
285 values.
286
287 - `BinaryOperation`
288
289 A continuation which posesses a property `value` and
290 which yields a value when continued by applying some
291 operation to `value` (treated as LHS) and the
292 accumulator (treated as RHS.)
293
294 - `Add`
295
296 A concrete binary operation which adds `value` to
297 the accumulator and passes the result when
298 continuing `next`.
299
300 - `Subtract`
301
302 A concrete binary operation which subtracts the
303 accumulator from `value` and passes the result when
304 continuing `next`.
305
306 - `Multiply`
307
308 A concrete binary operation which multiplies `value`
309 by the accumulator and passes the result when
310 continuing `next`.
311
312 - `Divide`
313
314 A concrete binary operation which divides `value` by
315 the accumulator and passes the result when
316 continuing `next`.
317
318 - `Condition`
319
320 A BinaryOperation which yields a boolean value.
321
322 - `Equal`
323
324 A concrete binary operation which compares
325 `value` to the accumulator and passes True when
326 continuing `next` only if they are equal.
327
328 - `GreaterThan`
329
330 A concrete binary operation which compares
331 `value` to the accumulator and passes True when
332 continuing `next` only if `value` is greater.
333
334 - `Print`
335
336 A concrete continuation which displays the value of the
337 accumulator to the user before continuing its `next`
338 property.
339
340 - `Input`
341
342 A concrete continuation which obtains a value from the
343 user, and passes this value in the accumulator when
344 continuing its `next` property.
345
346 - `Branch`
347
348 An abstract continuation which continues one of the
349 continuations assigned to its properties, based on some
350 other information. Defines the `Chain` property `else`
351 which represents the basic alternate continuation that
352 can be continued instead of `next`.
353
354 - `If`
355
356 A continuation which continues one of two
357 continuations assigned to its properties, `next` and
358 `else`, based on whether the accumulator is an
359 instance of `True` or `False`.
360
361 - `Switch`
362
363 An abstract continuation whose behaviour differs on
364 subsequent times it is continued. This is
365 implemented by means of a `state` property which
366 changes values each time the switch is continued;
367 depending on the value of `state`, different things
368 happen.
369
370 - `Loop`
371
372 An abstract continuation which is intended to
373 implement a loop. However, this is not
374 automatic; some continuation chain leading from
375 this continuation *must* lead back to this
376 continuation in order for actual repetition to
377 take place.
378
379 - `WhileLoop`
380
381 A concrete `Loop` which, on odd visits
382 continues its `test` property. It is assumed
383 that some continuation down that chain
384 continues this `WhileLoop` object with a
385 boolean value in the accumulator. On these
386 even visits, it will behave like an `If`:
387 when the boolean is a `True`, `next` is
388 continued, otherwise `else`.
389
390 - `ForLoop`
391
392 A concrete `Loop` which defines `value`,
393 `delta`, and `finish` properties, all
394 `Integer`s. On each visit, it checks if
395 `value` equals `finish`; if not, it adds
396 `delta` to `value` and continues `next`. But
397 if so, it simply continues `else`.
398
399 Implementations
400 ---------------
401
402 There is not currently a reference implementation of Unlikely. Any
403 contradictions and/or grey areas in this document will therefore have
404 nowhere to turn to to be cleared up.
405
406 There is, however, a partial and non-normative implementation of
407 Unlikely, a static analyzer written in Python called Coldwater. It
408 parses Unlikely programs and identifies many type errors and other
409 statically-detectable invalid programs. It is meant to give some body to
410 the ideas present in Unlikely, without actually going so far as
411 implementing it in full.
412
413 The construction of Coldwater helped clear up some of the fuzzier
414 corners of the language. However, there are probably several areas that
415 remain fuzzy and render the language unsuitable for anything but the
416 most trivial programming. Extending Coldwater to be a full-fledged
417 Unlikely interpreter will probably help define the language. However
418 that project has been deferred as future work, and any clarifications
419 that come from it will be incorporated only in a future language
420 version.
421
422 Discussion
423 ----------
424
425 This section contains some random thoughts and reflections on the
426 Unlikely programming language.
427
428 There is a rough analogy between Unlikely's requisite dependency
429 injection class parameters, and value parameters in languages without
430 global variables. There is no implicit referent when you say `Foo`;
431 `Foo` must name some parameter that has been passed into scope.
432
433 Because all the parts of the language are modelled as objects, the
434 language's execution model has some resemblance to an object-oriented
435 AST interpreter for itself. Except, of course, these objects are
436 continuations, so it is not like a recursive, depth-first walk of the
437 AST; it is much closer to the technique of threading the AST and
438 following that thread.
439
440 At one point I included the constraint that the set of dependant classes
441 specified by a class must be mutually disjoint; that is, no dependant
442 class in the set could be a subclass of some other dependant class in
443 the set. I am not entirely sure why I introduced that constraint, since
444 it could well be valuable to refine two classes by injection even when
445 one of those classes is a subclass of the other. I took it out.
446
447 Because properties cannot be redefined in subclasses, and because
448 parameters to methods are just syntactic sugar for properties, methods
449 cannot be overloaded. In particular `continue` must always work on a
450 `Passive` parameter, although of course it is mere convention that the
451 method works on the `accumulator` property anyway.
452
453 Unlikely is Turing-complete. (I will assert this because it seems
454 reasonable to me, but I do not have a proof, so I may be wrong.) The
455 Unlikely language is not minimal. In particular, the `Loop` class and
456 its subclasses `WhileLoop` and `ForLoop` could be removed, and the
457 resulting language would still be Turing-complete. In fact, `WhileLoop`
458 and `ForLoop` could probably be implemented in Unlikely and provided in
459 an extension class library.
460
461 The idea to conflate contintuations and objects was inspired by the
462 data-structure representation of continuations in Chapter 7 of
463 [Essentials of Programming Languages, 2nd
464 ed.](http://www.cs.indiana.edu/eopl/), which embodies a tiny measure of
465 inheritance. The idea that language constructs have commensurate
466 inheritance relationships (`WhileLoop` and `ForLoop` are subclasses of
467 `Loop`, etc.) was borrowed from Steve Yegge's article [Scheming is
468 Believing](http://steve.yegge.googlepages.com/scheming-is-believing).
469 The idea that all programs are subclasses of `Program`, which dovetails
470 so nicely with that, was borrowed from Brian Connors' "Sulawesi"
471 language design. The idea that every concrete value has its own class,
472 leading to abstract final classes with countably infinite subclasses,
473 was pure desperation.
474
475 For the purpose of defining computable functions, the Unlikely-Calculus
476 could be considered as a variant of Unlikely without `Print` or `Input`
477 classes. The `Stop` class would be there redefined to yield the value
478 passed to the accumulator as the result of evaluation, rather than as an
479 operating system exit code.
480
481 It's a safe bet that there is at least one person out there who will be
482 disappointed that this language is named Unlikely yet contains no
483 probabilistic design features.
484
485 Happy object-method-continuing!
486 Chris Pressey
487 March 15, 2009
488 Bellevue, WA
0 The Unlikely Programming Language
1 =================================
2
3 Overview
4 --------
5
6 Unlikely is a programming language with the following traits:
7
8 - Unlikely conflates objects with continuations, and methods with
9 labels. All classes are subclasses of the root class `Continuation`.
10 Every object can be continued at any method. Every method, except
11 for the `continue` method on the built-in class `Stop`, must
12 continue some other method at the end of its definition.
13 - All Unlikely program structures are exposed as objects with
14 commensurate inheritance relationships. For example, every Unlikely
15 program is a subclass of `Program`, and the classes `If` and
16 `Switch` are both subclasses of the abstract base class `Branch`.
17 - Unlikely takes dependency injection to the logical extreme.
18 Dependency injection is an increasingly popular modern
19 object-oriented program construction technique which allows the
20 specific classes which will be used by some class ("dependencies")
21 to be specified ("injected") when that class is instantiated.
22 Unlikely goes one step further by *requiring* that all specific
23 classes used by some class are specified during instantiation.
24
25 Semantics
26 ---------
27
28 ### Classes
29
30 A class is a schema describing a set of objects. Instantiating a class
31 produces a new object of that class. When a class is instantiated, all
32 classes that are referenced by the class (dependant classes) must be
33 named (injected) by the instantiating code (the instantiator). For each
34 requested dependant class, any subclass of it may be supplied by the
35 instantiator, further specifying and constraining behaviour (a technique
36 called dependency injection). In this way, classes are inherently
37 parameterized.
38
39 When a class refers to itself, it is considered a dependant class of
40 itself; it (or a subclass) must be injected by the instantiator.
41
42 All specified dependant classes must be unique (no dependant class may
43 be specified more than once.) Final classes need not and may not be
44 specified as dependant classes because, being final, there is no
45 subclass that the instantiator could possibly substitute for them.
46
47 Each class may define zero or more properties and zero or more methods.
48
49 #### Inheritance
50
51 Whenever a class is defined in Unlikely source code, a superclass must
52 be named; the class being defined is thus a subclass that inherits from
53 that superclass. Its inheritance consists of the properties and methods
54 defined by the superclass and all of its ancestors (i.e. including all
55 properties and methods that the superclass inherited from its own
56 superclasses) as well as the dependant classes of the superclass. The
57 subclass may not inject dependencies when inheriting from a superclass.
58 Only single inheritance is supported.
59
60 A subclass may override methods that it inherits from its superclass. It
61 may access the method definition of its direct superclass (or any
62 indirect ancestor class) by naming that superclass explicitly in a
63 continue.
64
65 A class may be declared as final, in which case it may not be
66 subclassed. In addition, final dependant classes may not be injected.
67
68 A class may also be declared as saturated, in which case it can be
69 subclassed, but subclasses of it must also be declared as saturated, and
70 they cannot define any new methods. They can only override existing
71 methods. In fact, the root class `Continuation` is declared saturated,
72 so really, all objects have exactly one method, `continue`.
73
74 If a class defines or inherits any abstract methods, that class must be
75 declared as abstract. Abstract classes cannot be instantiated. Any
76 subclass of an abstract class must define all inherited abstract methods
77 in order to be considered concrete and thus instantiatable.
78
79 ### Properties
80
81 Each property has a particular type, which is a class. The values it may
82 take on are objects of that class, or of its subclasses.
83
84 Each object has its own instances of the properties defined on the
85 class, and each of these properties may take on different values.
86
87 All state of an object is stored in its properties. Properties are
88 effectively public; they can be modified by code in any method in any
89 class.
90
91 The root class `Continuation` defines one property, `accumulator`, of
92 type `Passive`, which all classes inherit.
93
94 Subclasses may not override inherited properties.
95
96 ### Methods
97
98 A method is a label on a piece of code inside a class. The methods of a
99 class are shared by all objects of that class.
100
101 A method may be declared abstract instead of defining code for it.
102 Classes which contain abstract methods must themselves be declared
103 abstract.
104
105 Only one thing may be done to a method in code, which is to continue it
106 with respect to some object; this is described in the next section.
107
108 A method may declare zero or more arguments. Each argument has a type,
109 which is a class. When a method is continued, a value of the
110 corresponding type (or some subclass of that type) must be given for
111 each argument. In actuality, the arguments merely name properties of the
112 object; they must already be declared in the class before they are
113 listed in the declaration of the method. Passing values in arguments is
114 just shorthand for assigning these properties before continuing the
115 method.
116
117 Methods do not have local variables, so for storage must use the
118 properties of the object on which they were continued.
119
120 The root class `Continuation` defines one abstract method which
121 subclasses must implement, called `continue(Passive accumulator)`. By
122 convention, this method is what other methods continue. The accumulator
123 is passed from continuation to continuation, manipulated as execution
124 proceeds.
125
126 ### Code
127
128 The code inside a class labelled by a method consists of a series of
129 assignments followed by a continue.
130
131 Each assignment consists of an object property on the left-hand side,
132 and an expression on the right-hand side. The the property so named will
133 take on the value resulting from evalulating the given expression.
134 Expressions consist of instantiations of new objects, and references to
135 other object properties.
136
137 The continue names a method on an object to which control flow will
138 immediately pass. It may also pass values as arguments to that method;
139 however, this is mere shorthand for assigning properties of the object
140 on which the method being continued is defined. See above under
141 "Methods" for more details.
142
143 ### Passive Data
144
145 Passive data values, such as integers and strings, are modelled somewhat
146 specially in Unlikely, in order to strike a balance in language design
147 between "too straightforward" and "too convoluted".
148
149 All passive data values are instances of some subclass of the abstract
150 class `Passive`, which is itself a subclass of `Chain`. When a passive
151 data value is continued, it passes its own value into the accumulator of
152 the "next" continuation. (It is not necessary, however, to continue the
153 passive data value to obtain its value in all cases.)
154
155 Each immediate subclass of `Passive` gives a data type of values, such
156 as `Integer` or `String`. Each of these type-classes has a countably
157 infinite number of subclasses, one for each possible value of that type.
158 It is these classes that are instantiated to acquire a passive value
159 object. For example, `three = new 3()` instantiates the value 3. When
160 the `continue` method on this object is continued, the value that it
161 represents will be passed down the chain to the continuation assigned to
162 its `next` property. For example, `three.next = new Print()` would cause
163 3 to be printed when `three` was continued.
164
165 None of the direct subclasses of `Passive` can be further subclassed. In
166 effect, they are final (despite being abstract!) because all possible
167 subclasses of them already exist.
168
169 Syntax
170 ------
171
172 ### Overview
173
174 The overall schema of a class definition is:
175
176 class ClassName(ClassName,ClassName) extends ClassName {
177 ClassName propname;
178 method methodname(ClassName propname, ClassName argname) {
179 propname = new ClassName(ClassName,ClassName);
180 propname.propertyname = argname;
181 goto expr.methodname(expr,expr);
182 }
183 }
184
185 ### Grammar
186
187 A somewhat more formal definition of the syntactic structure of Unlikely
188 code is given in the following EBNF-like grammar.
189
190 ClassBase ::= {ClassDefn}.
191 ClassDefn ::= "class" ClassName<NEW> "(" [ClassName {"," ClassName}] ")" "extends" ClassName
192 ["{" {PropDefn} {MethodDefn} "}"] ["is" ClassMod {"and" ClassMod}].
193 ClassMod ::= "final" | "saturated" | "abstract".
194 PropDefn ::= ClassName PropName<NEW> ";".
195 MethodDefn ::= "method" MethodName<NEW> "(" [ParamDecl {"," ParamDecl}] ")"
196 ("{" {Assignment} Continue "}" | "is" "abstract").
197 ParamDecl ::= ClassName PropName.
198 Assignment ::= QualName "=" Expr ";".
199 Continue ::= "goto" PropName "." MethodName "(" [Expr {"," Expr}] ")" ";".
200 Expr ::= ConstrExpr | QualName.
201 ConstrExpr ::= "new" (ClassName | Constant) "(" [ClassName {"," ClassName}] ")".
202 QualName ::= PropName {"." PropName}.
203 ClassName ::= <<sequence of alphabetic characters>> | Constant.
204 Constant ::= <<sequence of decimal digits>> | <<sequence of arbitrary characters between double quotes>>.
205
206 Note that multiple ClassDefns for a single class may appear; each may
207 partially define the class. In this way a "forward declaration" of a
208 class may occur. This may give its name, superclass, and dependant
209 classes, so these can be consumed by some following class that requires
210 them, before the methods of this class are defined. The dependant
211 classes are cumulative over successive partial definitions; they need
212 not be repeated. However the same superclass must be specified for all
213 partial definitions of a class.
214
215 Built-in Classes
216 ----------------
217
218 - `Continuation`
219
220 The abstract base class that is the superclass of all Unlikely
221 classes, and which can't be instantiated. Declares the property
222 `Passive accumulator`, and the abstract method
223 `continue(Passive accumulator)`, which all concrete subclasses must
224 implement. Is declared `saturated`, so no subclass may declare or
225 define any additional methods.
226
227 - `Program`
228
229 An abstract continuation that provides the guarantee that it can
230 be started (that is, that its `continue` method can be initially
231 continued) from the operating system. It can be reasonably
232 expected that the `accumulator` will be assigned a value
233 provided by the user, perhaps via a command-line argument.
234
235 - `Stop`
236
237 A concrete continuation which exits to the operating system
238 when continued. The accumulator is used as the exit code,
239 assuming the operating system supports this.
240
241 - `Chain`
242
243 An abstract continuation which defines the property
244 `Continuation next`. When a subclass of `Chain` is
245 continued, it will generally continue the continuation
246 assigned to its `next` property after doing something.
247
248 - `Passive`
249
250 The abstract final base class representing passive data
251 values. Discards whatever accumulator was passed to it,
252 and passes its own value into the accumulator when it
253 continues the continuation assigned to its `next`
254 property.
255
256 - `Boolean`
257
258 The abstract final base class representing boolean
259 values.
260
261 - `True`, `False`
262
263 Final classes representing particular boolean
264 values.
265
266 - `Integer`
267
268 The abstract final base class representing integer
269 values.
270
271 - `0`, `1`, `2`...
272
273 Final classes representing particular integer
274 values. Note that only positive constants are
275 available; negative values must be computed by
276 subtracting from 0.
277
278 - `String`
279
280 The abstract final class representing string values.
281
282 - `""`, `"a"`, `"b"`, `"aa"`...
283
284 Final classes representing particular string
285 values.
286
287 - `BinaryOperation`
288
289 A continuation which posesses a property `value` and
290 which yields a value when continued by applying some
291 operation to `value` (treated as LHS) and the
292 accumulator (treated as RHS.)
293
294 - `Add`
295
296 A concrete binary operation which adds `value` to
297 the accumulator and passes the result when
298 continuing `next`.
299
300 - `Subtract`
301
302 A concrete binary operation which subtracts the
303 accumulator from `value` and passes the result when
304 continuing `next`.
305
306 - `Multiply`
307
308 A concrete binary operation which multiplies `value`
309 by the accumulator and passes the result when
310 continuing `next`.
311
312 - `Divide`
313
314 A concrete binary operation which divides `value` by
315 the accumulator and passes the result when
316 continuing `next`.
317
318 - `Condition`
319
320 A BinaryOperation which yields a boolean value.
321
322 - `Equal`
323
324 A concrete binary operation which compares
325 `value` to the accumulator and passes True when
326 continuing `next` only if they are equal.
327
328 - `GreaterThan`
329
330 A concrete binary operation which compares
331 `value` to the accumulator and passes True when
332 continuing `next` only if `value` is greater.
333
334 - `Print`
335
336 A concrete continuation which displays the value of the
337 accumulator to the user before continuing its `next`
338 property.
339
340 - `Input`
341
342 A concrete continuation which obtains a value from the
343 user, and passes this value in the accumulator when
344 continuing its `next` property.
345
346 - `Branch`
347
348 An abstract continuation which continues one of the
349 continuations assigned to its properties, based on some
350 other information. Defines the `Chain` property `else`
351 which represents the basic alternate continuation that
352 can be continued instead of `next`.
353
354 - `If`
355
356 A continuation which continues one of two
357 continuations assigned to its properties, `next` and
358 `else`, based on whether the accumulator is an
359 instance of `True` or `False`.
360
361 - `Switch`
362
363 An abstract continuation whose behaviour differs on
364 subsequent times it is continued. This is
365 implemented by means of a `state` property which
366 changes values each time the switch is continued;
367 depending on the value of `state`, different things
368 happen.
369
370 - `Loop`
371
372 An abstract continuation which is intended to
373 implement a loop. However, this is not
374 automatic; some continuation chain leading from
375 this continuation *must* lead back to this
376 continuation in order for actual repetition to
377 take place.
378
379 - `WhileLoop`
380
381 A concrete `Loop` which, on odd visits
382 continues its `test` property. It is assumed
383 that some continuation down that chain
384 continues this `WhileLoop` object with a
385 boolean value in the accumulator. On these
386 even visits, it will behave like an `If`:
387 when the boolean is a `True`, `next` is
388 continued, otherwise `else`.
389
390 - `ForLoop`
391
392 A concrete `Loop` which defines `value`,
393 `delta`, and `finish` properties, all
394 `Integer`s. On each visit, it checks if
395 `value` equals `finish`; if not, it adds
396 `delta` to `value` and continues `next`. But
397 if so, it simply continues `else`.
398
399 Implementations
400 ---------------
401
402 There is not currently a reference implementation of Unlikely. Any
403 contradictions and/or grey areas in this document will therefore have
404 nowhere to turn to to be cleared up.
405
406 There is, however, a partial and non-normative implementation of
407 Unlikely, a static analyzer written in Python called Coldwater. It
408 parses Unlikely programs and identifies many type errors and other
409 statically-detectable invalid programs. It is meant to give some body to
410 the ideas present in Unlikely, without actually going so far as
411 implementing it in full.
412
413 The construction of Coldwater helped clear up some of the fuzzier
414 corners of the language. However, there are probably several areas that
415 remain fuzzy and render the language unsuitable for anything but the
416 most trivial programming. Extending Coldwater to be a full-fledged
417 Unlikely interpreter will probably help define the language. However
418 that project has been deferred as future work, and any clarifications
419 that come from it will be incorporated only in a future language
420 version.
421
422 Discussion
423 ----------
424
425 This section contains some random thoughts and reflections on the
426 Unlikely programming language.
427
428 There is a rough analogy between Unlikely's requisite dependency
429 injection class parameters, and value parameters in languages without
430 global variables. There is no implicit referent when you say `Foo`;
431 `Foo` must name some parameter that has been passed into scope.
432
433 Because all the parts of the language are modelled as objects, the
434 language's execution model has some resemblance to an object-oriented
435 AST interpreter for itself. Except, of course, these objects are
436 continuations, so it is not like a recursive, depth-first walk of the
437 AST; it is much closer to the technique of threading the AST and
438 following that thread.
439
440 At one point I included the constraint that the set of dependant classes
441 specified by a class must be mutually disjoint; that is, no dependant
442 class in the set could be a subclass of some other dependant class in
443 the set. I am not entirely sure why I introduced that constraint, since
444 it could well be valuable to refine two classes by injection even when
445 one of those classes is a subclass of the other. I took it out.
446
447 Because properties cannot be redefined in subclasses, and because
448 parameters to methods are just syntactic sugar for properties, methods
449 cannot be overloaded. In particular `continue` must always work on a
450 `Passive` parameter, although of course it is mere convention that the
451 method works on the `accumulator` property anyway.
452
453 Unlikely is Turing-complete. (I will assert this because it seems
454 reasonable to me, but I do not have a proof, so I may be wrong.) The
455 Unlikely language is not minimal. In particular, the `Loop` class and
456 its subclasses `WhileLoop` and `ForLoop` could be removed, and the
457 resulting language would still be Turing-complete. In fact, `WhileLoop`
458 and `ForLoop` could probably be implemented in Unlikely and provided in
459 an extension class library.
460
461 The idea to conflate contintuations and objects was inspired by the
462 data-structure representation of continuations in Chapter 7 of
463 [Essentials of Programming Languages, 2nd
464 ed.](http://www.cs.indiana.edu/eopl/), which embodies a tiny measure of
465 inheritance. The idea that language constructs have commensurate
466 inheritance relationships (`WhileLoop` and `ForLoop` are subclasses of
467 `Loop`, etc.) was borrowed from Steve Yegge's article [Scheming is
468 Believing](http://steve.yegge.googlepages.com/scheming-is-believing).
469 The idea that all programs are subclasses of `Program`, which dovetails
470 so nicely with that, was borrowed from Brian Connors' "Sulawesi"
471 language design. The idea that every concrete value has its own class,
472 leading to abstract final classes with countably infinite subclasses,
473 was pure desperation.
474
475 For the purpose of defining computable functions, the Unlikely-Calculus
476 could be considered as a variant of Unlikely without `Print` or `Input`
477 classes. The `Stop` class would be there redefined to yield the value
478 passed to the accumulator as the result of evaluation, rather than as an
479 operating system exit code.
480
481 It's a safe bet that there is at least one person out there who will be
482 disappointed that this language is named Unlikely yet contains no
483 probabilistic design features.
484
485 Happy object-method-continuing!
486 Chris Pressey
487 March 15, 2009
488 Bellevue, WA
1919 exit 1
2020 fi
2121
22 falderal $APPLIANCES tests/Unlikely.markdown || exit 1
22 falderal $APPLIANCES tests/Unlikely.md || exit 1
+0
-45
tests/Unlikely.markdown less more
0 Tests for Unlikely
1 ==================
2
3 -> Tests for functionality "Parse Unlikely Program"
4
5 Here is a syntactically correct program.
6
7 | class Count(Count,Chain,Print,Add) extends Continuation
8 |
9 | class CountForever(Count,Chain,Print,Add) extends Program {
10 | Count c;
11 | method continue(Passive accumulator) {
12 | c = new Count(Passive,Count,Chain,Print,Add);
13 | goto c.continue(new 1(Passive));
14 | }
15 | }
16 |
17 | class Count() extends Continuation {
18 | Count c;
19 | Print p;
20 | Add a;
21 | method continue(Passive accumulator) {
22 | c = new Count(Passive,Count,Chain,Print,Add);
23 | a = new Add(Passive,Chain);
24 | a.value = new 1(Passive);
25 | a.next = c;
26 | p = new Print(Passive,Chain);
27 | p.next = a;
28 | goto p.continue(accumulator);
29 | }
30 | }
31 |
32 =
33
34 And here is one which is not syntactically correct.
35
36 | class Hello(Print,Chain,Stop) extends Program {
37 | Print p;
38 | method continue(accumulator) {
39 | p = new Print(Passive,Chain);
40 | p.next = new Stop(Passive);
41 | goto p.continue(new "Hello, world!"(Passive));
42 | }
43 | }
44 ? ArtefactNotFoundError
0 Tests for Unlikely
1 ==================
2
3 -> Tests for functionality "Parse Unlikely Program"
4
5 Here is a syntactically correct program.
6
7 | class Count(Count,Chain,Print,Add) extends Continuation
8 |
9 | class CountForever(Count,Chain,Print,Add) extends Program {
10 | Count c;
11 | method continue(Passive accumulator) {
12 | c = new Count(Passive,Count,Chain,Print,Add);
13 | goto c.continue(new 1(Passive));
14 | }
15 | }
16 |
17 | class Count() extends Continuation {
18 | Count c;
19 | Print p;
20 | Add a;
21 | method continue(Passive accumulator) {
22 | c = new Count(Passive,Count,Chain,Print,Add);
23 | a = new Add(Passive,Chain);
24 | a.value = new 1(Passive);
25 | a.next = c;
26 | p = new Print(Passive,Chain);
27 | p.next = a;
28 | goto p.continue(accumulator);
29 | }
30 | }
31 |
32 =
33
34 And here is one which is not syntactically correct.
35
36 | class Hello(Print,Chain,Stop) extends Program {
37 | Print p;
38 | method continue(accumulator) {
39 | p = new Print(Passive,Chain);
40 | p.next = new Stop(Passive);
41 | goto p.continue(new "Hello, world!"(Passive));
42 | }
43 | }
44 ? ArtefactNotFoundError