Rethinking Mantra

Skip to end of metadata
Go to start of metadata

random thoughts dump as I consider new version

starting from barebones Smalltalk, what would a language look like with mixins, static types, generics? For my graduate class in programming languages, I'm asking the students to build a complete Smalltalk interpreter and compiler. my implementation was 2500 lines of Java code including a bunch of smalltalk to implement Object and some libraries. I really enjoyed writing code in such a simple language that I could get my small brain wrapped around. it made me start thinking about a statically typed version. I started scribbling down notes after looking at various statically typed languages: Thinking about programming language productivity. I just looked back through my mantra design. It's not actually that bad!

seems like we need classes, mixins, and single inheritance. because of static typing, generics are a great way to avoid typecasts. I would also only require types on fields (unless initialized and obvious) and function signatures. Local variable types could be inferred. Let's make everything an object also. Change [...] to {...} so we can use [] for array reference.

Crap. that's almost exactly java; 'course no casts in there (wink) I guess Java stripped down is ok but we need to integrate closures well.

Code re-use

Key productivity: code reuse. how to get it? Inheritance/polymorphism is cool because the same code can work on more than just one kind type. I'm coming to the conclusion that being able to reuse code relies heavily on being able to pass an little code snippets to customize. For example, you can store all the boilerplate code for walking data structures in their respective types and then pass in actions. To make this work right, the code snippets have to be closures: they have to be able to see the surrounding environment even when they're executed elsewhere.

 Passing and code snippets seems to make it less useful to have generators ala Python and Ruby.  Just pass in what to do at each iteration instead of having it return a stream of objects. So, don't do it for each on an iterated value. pass in what to do at each node in the data structure.

We can also get away without the Some<T> vs None issue. For example, hash tables with get(key) can either return the element or null, but what if the map to value is null? A number of modern languages use Some/None so that get() returns a wrapped value. The problem is that you have to then deconstruct the result with a switch or some other verbose structure. It's better to simply do what Smalltalk doesn't pass in the code snippet that says what to do if you fail:

The other benefit is that you can do your own control structures

Another  problem I see all the time is that you want to alter the behavior of a class and so you subclass it, refining some methods or adding some. but, nobody creates these kinds of objects. you have to have a factory that knows whether to create the standard kind of objects or the specialized version.

 code reuse from inheritance is largely a byproduct of creating a correct inheritance hierarchy. Dog gets to reuse code from animal but it makes no sense to try to reuse code from animal inside, say, Truck. mixins allow us to break code out into different chunks and then combine them, but how to we refine an existing class? We essentially want to swap out the old class for the new. We're trying to customize software but in order to change that class, I then have to go build a factory  for every class. Again, the answer might involved passing in a code snippet to customize.

Just the other day I wanted to alter the way CommonToken printed out one of the tokens. I can easily refine a class by using inheritance and overriding toString. often this is not convenient because I want to alter the guts of the original method and calling super.toString() is often a blunt instrument to do that. I have to peel off the special cases below and then call super. It might be better to pass in snippet. Anyway, fine. I modified the definition of toString by inheritance. the problem is nobody creates my special class of token. so I have to go into my code that invokes the parser and pass in the factory; in java this is pretty annoying to create the class and so on. passing in {int t | new MyToken(t)} might be a lot easier. ANyway, the point is that inheritance didn't solve my problem. I needed to add a factory as well. that is a dynamic dependency code and is proven a hassle in practice.

We could add dynamic delegation and dynamic override but I think that that is asking for trouble. In most cases, altering behavior should be statically declared. Adding methods or fields would be okay dynamically.

 try to use reflection to look up the method of java. now add three or four different catch Exception blocks to catch all the stupid exceptions come out. Now, I understand that they need to indicate what went wrong, but exceptions aren't the answer. It's better to simply passing code to handle the " doesn't exist" case or " no permission" case, just like we did for the fetch from a hash table case above. the overuse of exceptions in Java is one of the most annoying things about it.

Syntax

Functions/methods

SmallTalk is

and then a at: 3 put: "hi".  What if we allowed 2nd syntax: a.atput(3,"hi"). Could be nice for stuff like sin(3.14159) but sin: 3.14159 ain't bad.

I prefer SmallTalk syntax when I need to pass code blocks. lets us make nice new control structures:

whereas

is much less nice.

sometimes smalltalk is too much; have to name args twice really. java:

smalltalkish:

allowing both kinds might be ok:

Grrr...simplicity demands one way.

One big annoyance is self self self in smalltalk and python. should assume self:

better:

Methods w/o args could be just:

or

should make methods/vars in same name space for clarity

What would a b c mean? Send a to self then b to that result then c to that result.

fields and methods w/o args would look same: f and m but f; as statement is illegal. how do we set a field of another object then?

e name = 'parrt'

won't work but we don't have dot. e.name = 'parrt' is best. hmm...maybe

e name: 'parrt'

so we implicitly define 'f:' for every field f? we could make '.' the field operator but then we can't automatically change every ref to field with method by defining "getter". a refactoring tool would do it like java I guess. yeah, '.' is good. e.funcname would be illegal.

Heh, then methods w/o args look like fields (properties ala C#?)

smalltalk puts methods in weird place

code block has whileTrue: and number has to: for ranges etc... Plus, I find

hard to pick out amongst all the messages. this is better:

To make our own control structures, maybe we can put them in as methods of current class or above. Object would have while:do: and if:do:

or maybe they are so common we use built in:

Others can be methods like:

smalltalk ctors has example:

someMoney := (Money dollars: 5) + (Money cents: 5).

Of course any real Smalltalk'er would do this by adding a few extension methods to a few Number classes and writing this instead...

someMoney := 5 dollars + 5 cents.

Awesome til you realize you had to go modify class Number (and what? rebuild entire language if we're in a static language?) A dynamic mixin that added dollars and cents to Number would work. Isolates me from and prevents bloating of Number.

Like smalltalk, constructors are inherited so we don't have to repeat. No real notion of constructor.

overloading

I use overloading in java mainly for default args in constructors. can get rid of?

overload operators

maybe [] and maybe ',' but shouldn't allow generic ops, right?

Readonly objects/structures

don't want people messing with list when we send off

readonly stuff can be parallelized

typenames

String name;

is bad since it looks like sending name msg to String.

name:String;

is better I guess but ':' conflicts with msg args. looks like String is arg to name msg to self. maybe:

var String name;

or

var name <String>; // using Strongtalk notation sort of

See The Strongtalk Type System for Smalltalk

Labels: