1 NOTE - where to put stuff about "is natural a type, is non-zero a type (for div)"
3 Objects and polymorphism, and some standard chalenges
7 Object a record of operations
9 Operation a function specific to, and depending on, and part of, an obect
11 Expectation what an operation (in high level, abstract, programmer based sense) expects of
14 Behaviour a specification of what an object ('s operations) does
16 '' vs State behaviour can be modeled as procedure plus state
18 Types subset of behaviour that satisfies expectation
19 also a set of object which share this subset of a behaviour
21 sum of types of operations
23 Subtypes relation between behaviours
24 co variance/ contra-variance
27 Polymorphism two objects in the same type conform to same expectation and so can
28 equally be arguments to an operation
33 Behaviours(?) that don't fit the model
37 Parameterised behaviours
41 Class: this that creates object - the set of those object - hence like a type
45 declared in parent (field)
46 refined in various children
47 e.g. float: float a mult int b -> a.mult(floatfromint(b))
49 Matching of infix to operator done at compile time.
50 thus not usable in very generic functions
53 an object may have multiple orderings. i.e. subtype of ordered(thing) for various things.
54 may even be subtype of ordered(X) for specific X twice.
56 This subtyping is not so much what-it-is, but how-it-behaves and, like people, it may
57 behave differently in different circumstances
58 This is almost a HAS-A link - it HAS-A behaviour.
59 So how do we tell a routine to sort an array of things based on a particular behaviour.
60 One could make an object with a compare fn which takes to things and compares them,
61 and have a different object (class) for each behaviour. But that is rather gross.
62 What is really required is to tell the sort routine what message to send.
65 This is a really interesting issue.
66 Who creates an object: presumably the class...
67 when we convert an int to a float do we
68 1/ anint.convert-to-float - i.e. call an operation on the int object
70 2/ float.createfromint(anint) - i.e. call a create operation passing the int as arg.
72 For funcitonal languages, where objects are immutable, create must able to create all objects.
75 it may be desirable to define new functionality for a given type of object, function which
76 are defined in terms of the objects behaviour, not its implementation.
77 Adding functions normally requires subtyping, but what we are saying that that the new function
78 are a logical extension of the object. we are just elaborating what was already there.
80 to do this we define a new type which is a subtype and provide the implementation as a statement
81 that the new type elobarates, rather than refines, the old.
82 e.g. stat-real elaborates real
83 this would (almost) imply that
84 GLB(stat-real, float) elaborates float
89 integer is unimplementable as it is infinite, and some values will not fit in virtual memory.
90 However, many useful subsets of integer are implimentable.
91 We want a supertype which means "integer, or useful subtype thereof"
92 As some ops will overflow, we define the set of possible value to be the integers plus "overflow".
93 define e.g. Z(m) a+b -> overflow if a or b is overflow
94 -> (a+b) if a and b and a+b are < m in abs value
95 -> (a+b) or overflow if a or b or a+b > m in abs value
96 then if m > n then Z(m)+ is more specific then Z(n)+, so Z(m) is a subtype of Z(n)
97 yet we normally consider a smaller set to be the subtype...
99 integers and type subsumption:
100 one view of subtyping is that an object of a particular type can be used
101 when an object of a higher type is expected (because it IS of that type too).
102 If an 8bit integer is considered to be a subtype of a 16 bit integer, then
103 we would expect "if x.lessthan(200) then x.add(200)" to not overflow
105 If 16bit is subtype of 8bit, then will work.
106 anything an 8bit can do, a 16bit can do..
107 But while the object may be capable, the value might not be suitable.
108 ..but with "overflow" in our model, any value is suitable, though it might be overflow...
110 alternately, overflow might be modelled as an exception. i.e. the op does not return.
111 Z(m) a+b -> (a+b) if a+b < m in abs value
112 -> exception otherwise
113 then if 8bit is subtype of 16bit... no real difference
115 Want to say: 16bit.add(a,b) where a,b are subtypes of 16bit, result is 16bit
116 may still overflow, but there wont be any surprises.
118 So: Z(n) is the type/set of integers less than n in abs value.
119 operations are limited - maybe decimalise, isprime, isodd
120 Various classes exist which can create Z(n) by adding, multiplying etc.
121 these require arguments which are of a subtype.
122 To facilitate this, we want to be able, given a variable of a type, automagically choose a
123 class which is of that type.
124 If V is Z(100), want to choose (maybe) class Z(127) == signed(8).
125 ouch - we are upside down again...
126 values subset one way, types subtype the other
132 - find that paper about open/closed self -
133 binary operators - arithmetic.
137 This is often one of the hairiest parts of a language because various types want to
138 be treated in similar ways, and people like to avoid extra syntax.
140 There seem to be three inputs to a formatting request:
141 1/ the objects (values) to be formatted
142 2/ the detailed shape of the formats for each object (hex/decimal field width etc)
143 3/ the constant padding, and the ordering of the formatted values
144 (which is only almost always constant)
146 some parts of 2 are closely tied to 1, some to 3.
147 e.g. field width is probably 3's domain. but is useful with 1 to print part of a string.
148 keeping the inputs separate hazards consistant update
149 keeping them together hazards abstraction and maybe readability.
150 Thus a choice is probably appropriate. Let the programmer decide.
153 stdout.print("now is the ", time, " for ", all," ", good, " men to come to that aid of the ", party)
154 where time = now.asciitime(),
155 all = people.count.decimal,
156 good = if (random > 0.5) "good" else "bad",
159 hard to distill this format into a per-language file. leaves too much un answered.
161 different formats of a value are a bit like different subjects looking at an object.
162 "you think it is an integer, but I think it is 32 bit hex, uppercase"
163 so I might define "Address" which is an elaboration of int which defines
164 tostr as .hex(8,"0").toupper
166 The numerical paradox
167 n-bit integers seem to subtype 16bit is a subtype of 8bit
168 subranges subtype 0-255 is a subtype of 0-65536
171 A distinction between objects (concrete) and values (abstract).
172 look at casting in C - (int)float preserves value, (int)point doesn't really.
173 (int)char certainly doesn't.
175 or 16bit type defn from above somewhere includes all 32bit and 64bit objects.
176 an 8bit 5 is different from a 32bit 5 etc.
178 if we start treating objects differently from values, we are losing abstraction.
180 So we want the compiler/language to determine which representation is appropriate
181 and how to perform an operation.
182 Probably the most difficult to specify is dealing with loss of precision, as it is
183 expected. overflow, and to lesser extent underflow, can be deliberately avoided.
186 What types are INTRINSIC to a language.
188 1/ Boolean essential for decisions.
189 2/ Code - may be third class, but must exist.
190 3/ lamba- again, often of a low class
191 4/ sequence - as in args to a procedure, statements in code, subobjects in an object
192 nice to make this first class - very parameterised, anonymous type.
193 also bits in an integer?
194 Hmm <'cart,x,y> <'polar,r,theta>
195 or imaginary.cart(x,y) imaginary.polar(r,theta)
198 To what extent should type of variables be declared?
199 for very local variables which are assigned once, e.g. for loop variable,
200 it seems unnecesary to declare type. just keep scope local and deduce type from usage.
202 even at larger level, is "int" enough, or do we want "count" "label" "area" ...
206 problem of locking - protecting against unwanted concurrent access.
207 2 senarios - within and without.
209 within the methods of an object, the object may occasionally violate the invarant.
210 While the invariant is violated, the object must be single threaded.
211 Dangerous code segments could be bracketed somehow.
213 without an object, we may want to use an object assuming conf->mirrors[i].that we are only user.
214 i.e. singlethread is a behaviour we want, so we include it in required type
217 How to specify fork/join.
218 don't want it to be tooo automatic or we cannot have fine control.
219 maybe model threads of control as objects - have arrays of them etc??
223 Parsing is a very common sort of problem which must be very configurable.
224 wan't some wway to specify a parser - as a list of parsing objects?
225 const-string might be "extended" to have a parse method which matches the string.
228 Executables as objects?
230 for uniformity, as well as expressivity, it would be nice if executable code
231 were treated like an object - was sufficiently first class to be passed around.
233 IF a THEN b ELSE c FI
234 would be a.choose(b,c)
235 where true.choose(x,y) == x.execute
236 and false.choose(x,y) == y.execute
238 a.choose(b,c).execute
239 with obvious redefinition of true and false.
240 a;b would be a sequence object.
241 {sequence}.execute would be {sequence}.head.execute, then {sequence}.tail.execute
242 need some input to .execute, and some output. This is looking very functional...
244 "normal" lang have code elements which access/modify "local variable".
245 such code elements would have limited scope and so could not be stored in variables
246 of greater scope. if scope is a part of a variables/values "type" then this can be
248 naturally, code elements could be created which have global scope. This needs a lamba
251 methods have the scope of an object, and are assigned to fields in that object.
252 Is each procedure (block?) call a creation of an object? like Beta?
253 Calling a method creates an object with fields which are the arguements and local vars,
254 enstacks the object, and proceeds to execute the .code sequence.
255 The objects in a .code sequence are method calls. Each identifies a target object, a
256 target method of that object, and a list of objects as arguments.
258 an object maps a methodname to a method.
259 a method maps an object to a (more specific) method.
260 eventually (After all args collected) a method maps an object to an object.
261 Hmmmm. an object maps a methodname to a method which is a new scoped execution object.
262 given an arguement, this executes.
263 That sees procedure parameters as a single sequence.
265 This is a bit wishy washy, but seems to tend toward a nice simple execution model...
266 What do I particularly want:
267 scope executable which can be passed down/around and optionally executed later.
268 unscoped lambda expression - i.e. an independant object!
269 combination - a scoped lambda expression.
271 BUT: What are the semantics of an atomic execution. is it value transformation ala functional
272 lang, or state change (of some scoped/stacked object) or both?
275 Subtyping objects is an illusion.
276 Subtyping of values makes lots of sense. Values don't change.
277 Subtyping of mutable objects just doesn't work. The objects of the sub type
278 must behave like objects of the supertype, and hence be subject to any change
279 that the supertype may be subject to.
280 Thus the invarient can only become less restrictive, thus allowing more value.
281 This is the integer subrange vs n-bit int distinction again.
283 So with typing, we focus on sub-types of VALUES of objects, and
284 type function to express types of objects.
285 The value of an array of ints is a subtype of the value of an array of objects,
286 but an array-of-ints object is a restriction of an array-of-objects object.
287 Clearly parameterised classes will play a bit role here.
289 SubObject references.
290 It is often desirable to have a pointer into a bag object such as a
291 linked list, a skip list, etc.
292 This is more than just a handle on a subobject as it may be used to
293 navigate around the structure.
294 Particularly in a multi-thread envronment, the bag object needs to
295 keep track of what active pointers there are too its sub objects, so
296 it can guard against deleting/changing an active object, or maybe an
297 object on an active path.
298 Requiring the client to "release" a reference is as bad as using
299 malloc/free. It is better to have language support - e.g. though
300 reference tracking. References must be released when pointers are
301 destroyed, and it is best if language system guarentees this.
302 This is like memmory allocation problem, except that a garbage
303 collect approach won't cut it.
305 Could possibly have several classes of references e.g. readonly and
306 read-write and ways to promote/demote them.
307 There is also a question of cutting a object up (e.g. double linked
308 list) and how that is type checked.....
309 Also, I like having a pointer to a thing that could be in one of
310 several doubly linked lists, and I don't care which one.
311 If I don't know, the compiler wont know, so how is concurrency
315 Objects without inheritance.
316 I have a feeling that when separated from subtyping, object
317 inheritance is purely an implementation convenience.
319 This convenience is possibly confusing and might be better
320 discarded. We can simply use object inclusion (has-a) and let the
321 compiler determine that a subobject can be inlined.
322 methods for the new class can be equated to methods on the sub
323 object or, quite naturally, a new method with calls a method on the
324 subobject. This discards super. calls and removes any name confusion
325 with multiple inheritance.
326 A question is self. calls. This is (after all) the most interesting
327 thing in oo programming. The routine in the superclass calls a
328 method in the subclass (which may, or may not be the same class).
330 One answer is my idea of extension classes which implement new
331 methods on objects of some known type interms of the external
332 interface to that object. e.g. sine(x) in terms of plus/mult/div etc.
333 Q. to what extend with the object be mutable??
335 Question. are safe downcasts needed. Are they like typecase in
336 modular-3? but there may be subthings you don't know about.
337 Should not you extend each possible subclass with the necessary
338 method. can this be done post-hoc. Is this just needed because
339 programmers don't really understand subtyping??
341 Java has an example (probably many) of safe downcasting..
342 A Hashtable is defined which maps objects to objects.
343 When you get an object out, the programmer probably knows the
344 type from the content of the key, but the language doesn't.
345 Hence a safe downcast is needed.
347 Two ideas present for making this more typesafe.
348 [ note safedown cast is not "typesafe" because it can through an exception]
349 1/ The key to the hash table could be
350 (key,type-of-content)
351 So store(key:object, ctype:type, content:ctype)
352 and fetch(key:object, ctype:type) : ctype
354 2/ The type can be explicitly stored with the content (instead of implicitly)
355 Then the table entry would be
356 <key:object, ctype:type, content:ctype>
357 It would be in either case.
359 This requires that types, or at least classes, exist as objects.
360 Q. are classes enough, or are all types potentially needed as objects?
361 we would really want a partial ordering, so all types are needed.
363 The next question is: who owns an operation like addition?
364 Addition of integers is a function of the set of integers (Z) more
365 than of any particular integer. 3.plus(4) always looked terribly asymetric.
366 If we think of objects more like values (which is pleasing for
367 numbers), then there are possibly many things we could mean by
368 "plus", modular arith for example.
369 Real-plus is the *same* op as integer-plus (as an integer IS a
370 real), but what about float-plus?
371 float is a REAL problem (joke!) because people want to treat it like
372 a real, but it simply ISN'T real (more-so than int isn't integer).
373 Possibly the semantics could be that a+b yields "real" addition, but
374 this value - which cannot be stored - gets converted to whatever it
375 gets stored in. e.g. a float or an int, which an implicit but
376 clearly acknowledged possible loss of information.
377 This doesn't quite work with nested expressions, as a difference of
378 two very close large numbers looses a lot of precision. We simply
379 cannot keep infinite precision (or even adequate precision)
382 I think I've lost the thread a bit though. That is a question of
383 overloading '+' and how to resolve that overloading.
384 ... but is it the same problem?
386 A problem with associating plus with "int" rather than "3", is that
387 if we have an object that we don't know is an int, how do we add to
389 Well, we must know that it is of a type that supports add (is that
390 ring? - probably ring-of-X) i.e. generic addition must be through
391 parameterised genericity rather than subtype genericity. (actually,
392 it's probably additive-group rather than ring).
395 We say "X == Additive-group of type X" is a type which supports the
396 binary operation "plus", thus is A and B are both of type X, then
397 "plus(A,B)" is of type X. (Additive-group "extends" X)
398 Then we can define an additive group of type "int", "float",
399 "matrix(n,m,scalar)", "0..6", where for each we must specify how
400 addition works in each case.
401 We can say that "X is an Additive-group(X)"
403 But if we see "plus(3,4)", what type is that? is it int.plus or
404 float.plus or "0..6".plus? If we want 3 to be simply the value "3",
405 equal in types 0..6 and int and float, then the plus must be decorated,
406 or the type must be propergated down from the receiving method(????)
408 If we use primarily one additive-group at a time, something like a
409 with-clause would suffice for briefness. But we may well be mixing
410 ints with floats, or anything else, and an accidental expectation of
411 int rather than modulo semantics would be confusing.
413 Maybe a low-cost with-clause on a per-expression basis:
414 int(3+4 div b) float(3/b+4/f) Zseven(4+5)
415 Without such clause, the least surprising would be used - int.plus
417 For non-operator methods, this isn't an issue. Just include type in
420 Rewind... When we say "X is an Additive-group of X", we need to
421 include the "of X" because if Y is a subtype of X, "Y is an
422 Additive-group of X", but probably not "of Y". or more importantly,
423 "of X" is more useful than "of Y".
426 An assertion: (did I make this earlier?)
427 subtyping mutable types doesn't make sense. Only subtyping of
429 The rationale is that the important use of subtyping is: is A is a
430 subtype of B, then a member of A can be used where ever a member of
432 Thus any change that is legal to a member of B MUST be legal to a
433 member of A, and the B-visible change will be the same.
434 Thus A must maintain the same state, and can only extend it with
435 more information. Yet B-acceptable changes will not usefully affect
436 the extra information......
437 Maybe not. A could contain a change history
438 Lots of other examples. A shape that can change colour...
440 So we can reasonably subtype all types.
442 Want to motivate result type being function of arg types.
443 choose(a,b:object) -> lub(a,b)
444 choose(a,b)+1 -> lub(additive-group/a, ag/b)
445 maybe say union rather than lub.
446 double(a) -> type-of(a), but what does that mean?
447 must choose significant point in type lattice between root and 2*a.
448 this probably what groups are about, but want more examples.
449 hmm. type info is static. this worth remebering. it is exactly what
455 An "Object" is a "thing" which has "behaviours".
456 By "thing" we mean that it is something that can be held (references, pointed to).
457 It is a bit like a black box.
459 Behaviours include (at least) responses (reactions).
460 A response is elicited when we send an(other) object to the object.
461 The response was three parts:
462 It produces an object.
463 It (may) change the original object into a different object
464 It may send other objects to other objects thereby causing other
465 objects to change into different objects.
467 So far it is pretty confusing. We need some structure.
469 A "type" is a set of "objects".
471 types will usually be prescriptive (is that the right word) meaning that any object which
472 fits the description is a member of the set.