Typed Systems, Type Inference, etc

David Simmons David.Simmons at smallscript.com
Sun Jul 21 07:03:01 UTC 2002


Just for consideration, here is what the actual point behavior
declaration looks like in SmallScript (abridged information, various
methods elided).

Class name: PointObject
    fields: virtual property x,y;
{
    "" Constructor(s)
    Function [<::(<>,<>)>
    x: x y: y
        ^new() x: x; y: y
    ].

    "" Instance method(s)
    Method [<'cloning'>
    + v
         ^class()(x + v, y + v)
    ]
    Method [<'cloning'>
    + <PointObject> pt
         ^class()(x + pt.x, y + pt.y)
    ] 
}

Where the alternate #::(<>,<>) class-method name, allows writing code as
follows:

Eval [
    "" SmallScript form
    |x := 10, y := 12|
    stdout cr << Point32(x,y).
]

Eval [
    "classic form"
    |x y| x := 10. y := 12.
    Transcript cr; nextPutAll: (Point32 x: x y: y).
]

Both of the above, will compile and behave correctly in SmallScript --
the use of <Transcript> instead of <stdout> requires a reference to the
"ANSI" library (module).

<PointObject> happens to be defined as a base-class (which is indicated
by the suffix "...Object"). We could just as easily have defined it as a
mixin with the same virtual field declarations.
==============
Translating the PointObject declarations to a more "classic Smalltalk"
format would read as:

Class name: PointObject
    fields: virtual property x,y;
{
    "" Constructor(s)
    Function ["removed the alternate method name"
    x: x y: y
        "explicitly reference <self> in #new"
        ^(self new) x: x; y: y
    ].

    "" Instance method(s)
    Method ["removed the 'cloning' category-tag annotation"
    + v
         ^(self class new) 
             x: (x + v) y: (y + v)
    ]
    Method [
    + <PointObject> pt
         ^(self class new)
             x: (x + pt.x) y: (y + pt.y)
    ] 
}

NOTE: Both forms shown here (original form, classic Smalltalk form) will
compile and produce the exact same code and behavior. With the noted
comments where I removed some extra annotations and replaced them with
comments.
==============

Given the above definitions, we can then create a variety of point
classes.

Class name: Point extends: PointObject
    fields: auto x,y.
Class name: Point32 extends: PointObject
    fields: auto struct int32 x,y.
Class name: Point16 extends: PointObject
    fields: auto struct int16 x,y.
Class name: PointFloat32 extends: PointObject
    fields: auto struct Float32 x,y.
Class name: PointFloat64 extends: PointObject
    fields: auto struct Float64 x,y.
===============

The significant point here is that we do not need to write *any* methods
for these various <PointObject> subclasses. They inherit all the
necessary behavior from the base class (which we could also have done
using an equivalent mixin). For example, 

That holds true, even though each of these point classes has a very
distinct representation for the field-types of its <x> and <y> fields.

----
SIDE NOTE: I make extensive use of mixins for managing GDI/User handle
object behavior and resource cache wrappers. It is also of significance
to recognize that a "virtual" field is one which does not have a "slot"
allocated for it in the physical object. 

If read/written then a per/instance field will become logically
available. The fact that it is a "property" means that all read/write
requests will actually be treated "logically" as "self field" and "self
field: val" messages [except within property getter/setter methods].

Finally, SmallScript provides intrinsic managed object behavior which
includes full control over all binding/invocation and read/write
operations. One of the features included in this facility are around,
before, inner (standard), and after methods. The "around" methods are
very important, and provide an invaluable addition to the designers
toolbox when working with mixins, and protecting framework base class
extensions from subclass refinement constraints.
----

In case it is not obvious, a Point32 is for all intents and purposes,
identical to a C++ declaration:

typedef struct 
{
    long    x,y;
} Point32;

It can be passed directly to external code, and can be automatically
marshalled from external code. Here would be a "real" example:

Eval [
    |pt| := Point32 new.
    User32::GetCursorPos(pt).
    stdout cr << pt.
]

Which is a direct Win32 call into the "User32.DLL" entry point
"GetCursorPos".

Or:

Eval [
    |pt| := Point32 new.
    GetCurrentPositionEx(canvas, pt).
]

Assuming the project imported the GDI32.DLL into its namespace scopes,
we do not need to qualify the call. We can just make it directly. Notice
that we did not need to declare type information anywhere. This is very
significant, and is one of the key ideas behind the dynamic type system
in SmallScript.

To access an arbitrary DLL one could do the following:
-----------------------------------------------------
Project name: MyProject imports: MyDLLBasedNamespace.
Namespace name: MyDLLBasedNamespace shared-library: MyDLL.dll.

Which, based on our prior example, could be used as follows:

Project name: MyProject imports: User32.
Eval [
    |pt| := Point32 new.
    GetCursorPos(pt).
    stdout cr << pt.
]

Hopefully, this provides some additional food for thought. Introducing
"types" into Smalltalk should be done with care and consideration. It
offers significant opportunity to enhance Smalltalk -- but there are
also classic static-typing concepts that may (depending on design goals)
be undesirable if the objective is to enrich Smalltalk for dynamic
typing behavior.

-- Dave S. [SmallScript Corp]

SmallScript for the AOS & .NET Platforms
David.Simmons at SmallScript.com | http://www.smallscript.org


> -----Original Message-----
> From: squeak-dev-admin at lists.squeakfoundation.org [mailto:squeak-dev-
> admin at lists.squeakfoundation.org] On Behalf Of Diego Gomez Deck
> Sent: Saturday, July 20, 2002 12:23 PM
> To: squeak-dev at lists.squeakfoundation.org
> Subject: Typed Systems, Type Inference, etc
> 
> Hi guys,
> 
> Smalltalk allow to write code with the minor possible coupling. An
object
> is coupled with other object only with the messages sent.
> 
> Point>>+ otherPoint
> 
> 	^(self x + otherPoint x) @ (self y + otherPoint y)
> 
> The only requirement for otherPoint is to answer #x and #y messages
[*].
> 
> [*] Answer a message don't means implement a method. Example: a object
> using #doesNotUnderstand: can answer to several messages without a
method.
> 
> 
> Let's see the StrongTalk implementation:
> 
> Point>>+ other <Point> ^<Point>
> 
> 	^(self x + other x)@(self y + other y)
> 
> Why this method require a "complete" Point?  In the not typed version,
the
> requirements is more relaxed.
> 
> This is the problem with typed systems.  The objects produced don't
grow
> in
> ways don't predicted by the writer.
> 
> 
> I think that some type of type annotations helps in the understanding
of a
> system and I see the problem with type inference.
> 
> My proposal is: Let's use Type Feedback to document a System.
> 
> Cheers,
> 
> Diego Gomez Deck
> 





More information about the Squeak-dev mailing list