Tuesday, October 04, 2005

Magik is so much like Smalltalk...

When I first started using Magik it came very easily and naturally to me since I had lots of previous experience with Smalltalk. In fact the languages are so similar that I'm not sure why Magik was even developed. In a lot of ways I find Magik to be a step backwards from Smalltalk, certainly in terms of the default debugging tools that are shipped with it and the lack of version management built into the image (ala Envy in the Smalltalk world). There are some key differences in the languages, though.

First, there is no such thing as a class object in Magik. In Smalltalk classes are objects and new instances of that class are created by sending the class object a creator method (usually called "new"). The class object is a different object from instances of that class. The class object is an instance of the object type "Class." In Magik no class object is every created. What gets created instead is an exemplar - the first and base instance of the class in question. This is exactly the same object as any other instance of the class. New instances are created by copying (using the _clone keyword) this exemplar.

Because Magik doesn't have any class objects there are no class methods like there are in Smalltalk.

Magik allows for multiple inheritance just like C++ but unlike Smalltalk. There are pluses and minuses with multiple inheritance with the main minus being the potential to get really screwy class hierarchies and unneeded complication. This was the reason it was removed when Java was designed. Of course, merely having this capability doesn't cause any problems, but the Smallworld system is rife with multiple inheritance. I'll explore some examples of how this is handy in future posts.

Bill

Tuesday, September 27, 2005

Dynamic Programming

Magik gives you the ability to call methods without knowing the name of the method at compile time. It does this via the perform method. With the perform method, which is defined on object and can therefore be sent to any type of object, takes a symbol as the first argument. This symbol is the name of the method to call. Any subsequent arguments to the perform method are passed to the invoked method. Here's an example:

MagikSF> r << rope.new()
$
sw:rope:[1-0]
MagikSF> r.add("hi")
$
"hi"
MagikSF> r.perform(:size)
$
1

You can do this with any type of method, including the square brackets method, as long as you create the symbol correctly with the vertical bars:

MagikSF> r.perform(:|[]|, 1)
$
"hi"

And you can even use the setter method:

MagikSF> r.perform(:|[]<<|, "joe", 1)
$
"joe"

MagikSF> r[1]
$
"joe"

Notice the strange order of the arguments to this method. I would have thought the index would have been the first argument, but it's not.

So, we can build up calls to objects by creating strings and then sending them as method names (really messages) to the object. What if we want to send a message to an exemplar where name of the exemplar is derived dynamically? To do this you use the square bracket method on the package containing the exemplar. Here's an example:

MagikSF> !current_package![:rope]
$
sw:rope:[1-1]

This stuff isn't used that much, but it can come in handy.

Thursday, September 22, 2005

Parsing Strings

A client new to Magik recently contacted me. He was frustrated with his failure to find out how to parse a string. While Magik, with its class browser, it much easier than most languages to figure this out, it can still be frustrating. The help files shipped with Smallworld are excellent and I recommend reading them often. They are very voluminous, but just read the section that prompted your search and then remember to return to it whenever you want a better understanding of the concept in question.

That said, the help files aren't the best place to search for this information. The class browser is usually your best bet. Fire that baby up (F3 F3) and enter "string" for the class. Now you have to guess what the method will be called. "parse" would certainly be your first guess in this case. Unfortunately, that isn't what the method is called and hence my client's frustration. Here there should be a topic in the help files to cover this very important area, but there isn't. So now you just have to guess. What is parsing? It is splitting up one string into many strings. So, if you search on "split" you'd find the method split_by(), which takes a single argument: a character upon which to split the string. Here's an example from the Magik prompt:

MagikSF> "123,456,hi joe".split_by(%,)

$

sw:simple_vector:[1-3]

MagikSF> print(!)

$

simple_vector(1,3):

1 "123"

2 "456"

3 "hi joe"

Here we split a string using the comma character as a separator. Note that a character object is created with the percent sign (%). This is just like the colon creates a symbol object and quotes create string objects. Also, the variable "!" is always set to the last value returned to the Magik prompt, hence I could print out the vector returned from the method split_by() using it. the split_by() method is sent to a string and it returns a vector of the parsed strings.

This client also wanted to turn a string of number characters into a number. There are a couple of ways to do this but the most natural is to use the as_number() method on string. This pattern is used often and many objects have as_object_class methods defined on them for conversion. Here is an example:

MagikSF> "123".as_number()
$
123

Why this blog?

This is my effort to collect some useful Magik programming hints, snippets of code, and discussion about the language. This programming language is only used inside of GE's Smallworld GIS product and hence has a very restricted audience compared to general programming languages. I am a principal consultant at Red Planet Consulting and I frequently teach classes on Smallworld and Magik. A number of students have asked me if there is a book that teaches this language. There is not, though I've thought about writing one many times. This is an area where I can collect my musings on the topic.

Bill