Let's see. Over 30+ years, the computer languages I have used professionally to earn a living have included Fortran, Assembler (of various sorts), Basic, dBase (II, III, and IV), SQL, Quel, Cobol, Dibol, C, C++, Java, Lisp, SmallTalk, Prolog, Snobol, sh, csh, bash, ksh, Ada and PL/SQL (a derivative of Ada), Transact-SQL, Perl, Python,... And a bunch more I don't remember any longer. Will it disappoint you that I have never used Nimrod? :-) I have looked at, but never used APL (though a mathematician friend of mine is a big proponent of it).
In any case, it sounds like a good example of my favorite language, YAPL. YAPL - Yet Another Programming Language. :-) Check it out, and let us know what you think.
There are some interesting design choices in Nimrod. I read the tutorial and it not only explained how to use the language; it also sometimes mentioned reasons for some of the features and many of those reasons are about efficiency. The compiler requires forward declarations because looking ahead would slow down compilation. Recursive types need to be defined together in a single type statement because, "anything else would require arbitrary symbol lookahead which slows down compilation." And multidimensional openarrays are forbidden because they are rarely needed and cannot be implemented efficiently.
Perhaps I have been spoiled by languages like Java and Haskell which are more concerned with helping me get things done than with doing things efficiently, but I would rather not have my language mandate that everything I write be manually optimized. If I write a program that takes a little longer to compile than it could, I still consider it the compiler's duty to compile it. It's my time to waste. And if I want multidimensional openarrays, then please accept that I don't care about efficiency and give me multidimensional openarrays.
Methods that have dynamic dispatch on all arguments is a nice feature. I expect there are some interesting things that can be done with that, though tracking down exactly what verion of a method might be ultimately called could be troublesome. At least with single dispatch it is easier to keep track of all the various versions of a method.
I don't mind minimalist support for object oriented programming in principle. After all, object oriented programming can be done in any language, but lack of multiple inheritence is troublesome. If you need a class that can take on more than one role, such as being passed to a sort procedure that expects a TList, but is also able to be passed to lookup that expects a TMap, then you need a work-around. It seems that you are forced to use composition in place of inheritence by creating an adapter class. For example, your class TBox could be a subclass of TList, and then you can have another class called TMapBox that is a subclass of TMap and contains a TBox.
Nimrod makes this relatively painless since classes can be defined with a brief notation and defining two classes in the same module gives them total access to each other's private members, but it seems far more confusing than it would be if TBox could have simply been both a TMap and a TList.
If multiple inheritence by adapter is difficult to read then it may be a part of a general carelessness toward reabability in the design of Nimrod. Another example is the concept of a var parameter which allows a procedure to modify a variable that is being passed as an argument. In C if you want to do that you pass the address of your variable and everyone can see you are doing that when the function is called. When this is done in Nimrod the arguments that might be modified look exactly like any other arguments; you just have to know that the procedure might be changing them.
I would have expected the use of var parameters to be discouraged, but it seems to be seriously encouraged. The built-in procedure new is used for dynamic allocation, but instead of returning a pointer to the new memory, it takes a pointer as an argument. Every procedure that returns a value also has a result variable which apparently exists mostly to make it easier for a procedure to return a value that it gets from a procedure call that modifies its arguments.
On the other hand I very much approve of how Nimrod makes parameters unmodifiable by default. The vast majority of functions never intend to modify their parameters, but parameters aren't declared to be const nearly as often because it is an unnecessary chore. I often wish that languages would stop asking us to flag parameters that can't be modified and instead ask us to flag parameters that can be modified.
Macros are a fun idea. They are awfully powerful, and when you want to get something done it is nice to feel that you have almost no limits, but it can't really be a good thing. Being able to read code easily is far more important than being able to write it easily, and when macros are involved it's hard to even be sure what language you are trying to read. I can't fault Nimrod for having a powerful macro system, but I hope it is used very rarely. It's disturbing that even the != operator is a macro.
I can't help but think that if the designers of Nimrod would put the cleverness that they put into the macro system into the rest of the language they could find a way to get rid of most of the need for macros. For example, there is the when statement which is essentially a macro version of an if statement, where if the when condition is true then the else clause doesn't even get type-checked. Deliberately not type-checking part of a program is surely a bad sign for reliability. You can even declare a variable inside a when and then use it outside the when. I don't see what all the dangerous trickery of when is trying to accomplish that couldn't be managed more safely with a simple if.
Nimrod certainly doesn't have traits like Scala. Nimrod is a very different language from Ruby, but I don't think Nimrod has anything that is really equivalent to mixins either.
My desire for multiple inheritence is entirely motivated by Nimrod's static type checking. Each procedure expects me to declare the types of every parameter. Under those circumstances, I expect the freedom to be able to declare my objects to be of more than one type. In Ruby you don't declare the types of your parameters, so the entire issue is avoided for that language.
One interesting powerful feature of Nimrod is the fact that you can add new methods to existing classes, even if the class is defined in another module. Ruby allows you to do almost the same thing, but when you do it in Ruby you are allowed to violate the privacy of the private members of a class, and fortunately Nimrod prevents this. Unfortunately, when you add methods in Nimrod you need to specify just one class; there is no way to make those methods available for other classes except by defining the methods again or having each class use up its one precious superclass slot.
Fortunately, according to its website Nimrod is still changing, so perhaps there is a chance that multiple inheritence will be added before version 1 is released and new features become much harder to add. For example, I think it would be entirely in the flavor of Nimrod to have a declaration something like:
extend TList: TCollection
where TList and TCollection are types declared earlier. TCollection would probably either be an object with no fields, or else a new kind of type specially added to the language for this purpose, but either way we would then have the power to call methods and procedures with a TList argument where a TCollection is expected. If you already have a big library of TCollection methods, then with one stroke you have brought all of that power into TList. You would probably also have to override a few TCollection methods to hook up the internals of TList to the TCollection interface, but it would still be enormously powerful.
It would be just like Ruby mixins but it would be type safe and you wouldn't be able to define new fields on your classes in the way that Ruby mixins can. Just like in Ruby you would be able to add the mixin anywhere in your source code, not just where your class is defined, so it fits in nicely with your ability to define methods anywhere in Nimrod.