New Year's Resolutions

A couple of years back, the Pragmatic Programmers had this sage advice:

Learn at least one new [programming] language every year. Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut.

For 2002, Haskell was presented as the LOTY choice - pretty good choice. But since that time, the authors became enamored of the Ruby way, and have failed to submit a nominee for subsequent annums. My personal choice for the coming year is tender young Alice. Anyone else have their dates picked out? Or are you all into the Language of the Week per our dear moderator?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Originally my choice was Erla

Originally my choice was Erlang, but the latest release of Alice is tempting me. I want to try some COP ideas now.

Down the Rabbit Hole

I think I learned exactly one language this year (C#), and carried on mucking around with maybe half a dozen others (Oz, Prolog, OCaml, Erlang, Scheme, Haskell).

This year I have my own copy of CTM to refer to, so COP is probably the way to go. Alice is certainly very cool, but Oz has the advantage of being the language most of the example code in CTM is written in. I'd also like to get more of a grip on capabilities, so if I were to make a resolution it would probably be to take a serious look at E.

Well, C# is kind of cheating...

...since it's just a slightly skewed version of Java with some different design decisions. :-)

I got some gift certificates which allowed me to do some impulse shopping today at the bookstore. Stumbled upon CTM and purchased it. Dang, we're not even a day into the new year, and my agenda has already changed. So much for New Year's resolutions.

I do plan to get back to Alice RSN, but I guess I'll be buried in CTM for a whilst. Then again, I played with Oz a couple of years back, so I don't think it qualifies as a new Language of the Year for my purposes.

Suggest away!

It isn't so much that we've become blinkered into mono-Rubyism. It's more that we're not much into leading projects such as this--we' rather folks take it upon themselves to try languages.

However, there are also folks who prefer learning things such as languages in a group. It'd be great if they could meet up on the mailing list and negotiate a language for 2005.

Cheers

Dave

New Languages

I'm still aiming for fluency in O'Caml and Oz... any day now.

My picks

1) For any programmer: Ruby
2) For the [ C | C++ | Java | etc ] programmer: Objective-C.
3) For the Objective-C programmer: Smalltalk.
4) For the Ruby programmer: Scheme.
5) For the Scheme programmer: Haskell.
6) For ALL programmers: Forth.
7) For the poor sap grinding out XML: any Lisp.

Next year, my language-to-try will be Erlang, as I'm interested in learning about its concurrency model.

For the Forth Programmer

Joy?

For anyone interested in rewriting/refactoring/proving/...

The above post is misleading. Joy has a superficial similarity to Forth. ie. Both are postfix stack based languages.

The real Joy of Joy is it's algebraic simplicity. There is a clear algebra ON Joy. You can algebraically manipulate and rewrite Joy programs. This is an incredible notion deserving far greater attention.

http://www.latrobe.edu.au/philosophy/phimvt/joy/j07rrs.html

More on Joy

here and check the LtU archive for more.

Joy == Functional Forth

Joy is what would happen if Forth and Scheme hooked up and had a child. Joy is really a kind of side-effect free version of Scheme, minus the lexically-scoped names, with automatic lexical closures replaced by a programmer-managed stack. :)
You can algebraically manipulate and rewrite Joy programs. This is an incredible notion deserving far greater attention.

I agree, although of course the same is true of any functional language (or at least the side-effect-free subsets thereof), and this has received a great deal of attention in certain circles. It deserves a lot more attention out in the commercial world, though.

Replace 6) by Joy.

Side note on 7), consider YAML instead of XML for serialization tasks.

Or in the same direction as your comment, consider Guile and Scheme hygenic macros.

So it's Ruby?

Since Scheme and Haskell I already know (as well as erlang)? It's been awhile since I found a new cool language...

Ruby is the new Python

Python is the new Java.

Java is the new COBOL.

Python is the new BASIC

It's more like "Python is the new BASIC," as it was specifically designed to be used by people new to programming.

Really?

Quoting from a page on the origins of Python:

I decided to write an interpreter for the new scripting language I had been thinking about lately: a descendant of ABC that would appeal to Unix/C hackers.

While such a claim isn't necessarily entirely unfounded, I doubt that the intention of the comparison was to equate "Unix/C hackers" with "people new to programming"...

ruby is not the new python

..it's the old visual basic (ok, an old one, but could not resist :)

Scala

I am learning Scala which is a nice blend of object and functional programming with full access to Java or .NET libraries.

CTM and Alice

Being one who likes to do things the hard way, I've decided to stick with Alice even though I intend to make my way through CTM. Ain't got too far, but here's the examples from part of the first chapter of CTM. Any criticisms are welcome. (Could of swore I saw some place where somebody had already worked through CTM for Alice, but I can't seem to find the reference).

And perhaps someone can point out the error of my ways on the optimized generacPascal (* in section 1.9 *) which gives a compile error under both Alice and SML-NJ?

Comments on CTM in Alice

I've decided to stick with Alice even though I intend to make my way through CTM.
You are brave indeed. I like the idea, although I'm pretty certain though that a lot of examples in CTM, being meant to show the multi-paradigm approach, are not easily translatable to Alice. I have not seen that being done before, but would definitely be interested.
Any criticisms are welcome.
Looks fine. I just wonder, why don't you use the Inspector for browsing?
(* the example of val v = 9999*9999 causes overflow. Must learn about bigInts in sml *)

In principle you just have to annotate the proper type to get overloading kick in:

val v = 9999*9999 : IntInf.int

In Alice however, overloading for literals has not been implemented yet (see limitations), so that an explicit conversion is required:

val v = IntInf.fromInt 9999 * IntInf.fromInt 9999

(* need to find out how to pattern match on a value in sml??? *)
Not sure what exactly you want, but you can either use case or do a declaration with a pattern:

val n::ns = bla

fun addInt(a, b) = a + b
This is redundant, you can just say op+ instead of addInt.
And perhaps someone can point out the error of my ways on the optimized generacPascal (* in section 1.9 *) which gives a compile error under both Alice and SML-NJ?
The let is simply missing an end.

Hopefully, Ehud will suffer me the specifics. :-)

I'm pretty certain though that a lot of examples in CTM, being meant to show the multi-paradigm approach, are not easily translatable to Alice.

Like most big projects I get involved in, if I knew how hard it was going to be before I started, I probably would never start. :-)

why don't you use the Inspector for browsing?

Started out cross-checking all the code in SML-NJ which doesn't have that feature. Code was changed to use the Inspector - which is much more in the spirit of Oz's Browse.

(* the example of val v = 9999*9999 causes overflow. Must learn about bigInts in sml *)

In principle you just have to annotate the proper type to get overloading kick in:

   val v = 9999*9999 : IntInf.int

I tinkered around with variations of IntInf.int but still haven't got anything to successfully compile. Specifically, the statement:

   val v = 9999 * 9999 : IntInf.int;

gives a compile error that says it can't unify int with IntInf.int.

(* need to find out how to pattern match on a value in sml??? *)

Not sure what exactly you want, but you can either use case or do a declaration with a pattern:
val n::ns = bla

What started me out on this line of thought was the oz code of:

   L=[5 6 7 8]
   case L of H|T then {Browse H} {Browse T} end

Lot's of ways to get the same functionality in SML, but in playing with it, I had two questions. First, is pattern matching limited to the functions? The Oz code allows you to pattern match the list, assigning the head and tail to local variables automatically. The second question is related to whether expressions can be used in the SML pattern matching.

   fun test []  = "A"
     | test [1] = "B"
     | test x   = "C";

That's pretty straight forward. But what if instead of using a constant in the expression of [1], I instead wanted to match to a variable value or an expression. Anyhow, it's just something I commented on that I want to revisit when I get my ML books in front of me.

This is redundant, you can just say op+ instead of addInt.

Added that variation in. Left the original in since it follows the CTM example code.

The let is simply missing an end.

Doh! (It was getting late). :-)

Sure

No worries mate.

Code was changed to use the I

Code was changed to use the Inspector - which is much more in the spirit of Oz's Browse.
Note however that you do not really need all the inspects, because the toplevel already prints the results anyway (unlike Oz).
val v = 9999 * 9999 : IntInf.int; gives a compile error that says it can't unify int with IntInf.int.
As I wrote, Alice does not yet implement SML's overloading on literals, so you have to use the explicit coercion I showed in my previous post.
case L of H|T then {Browse H} {Browse T} end

This translates directly to

case l of h::t => (inspect h; inspect t)

is pattern matching limited to the functions?
No, actually, they are just sugar for a case.
The second question is related to whether expressions can be used in the SML pattern matching.

Only by using guards (an Alice extension to SML):

fun test [x] where (x = y) = ...
| test _ = ...

I guess we should migrate further discussion on such details to the Alice user list, to avoid boring the other readers of LtU. :-)

Lambda lifting

Note however that you do not really need all the inspects, because the toplevel already prints the results anyway (unlike Oz).

Started out that way, but I'm running this from a file and Alice behaved a bit differently from the SML-NJ interpreter. It doesn't output the values, other than the last one from the script. Speaking of which, what's the default file extension for Alice (I'm just using .sml).

No, actually, they are just sugar for a case.... Only by using guards (an Alice extension to SML):

Thanks. Those are the exact constructs I was looking for.

I guess we should migrate further discussion on such details to the Alice user list, to avoid boring the other readers of LtU. :-)

I find it very interesting! But I suppose I'm getting the most out of the conversation. I've got a bloglines email account attached, and I almost started this secondary thread for the email. Will probably wind down and eventually resume over there. A lot of my questions are in trying to get into the ML mindset, and I don't know whether the preference is for Alice only type questions, or whether ML newbies like myself can meander in general.

Speaking of which, I'm kind of wondering whether basing the language on an extension to a current language will present barriers to entry. From the little I've worked with the extensions, I like what I see. But to get a real appreciation for the language, I can't help but think that being proficient in both SML and Oz (as it combines the concepts of one with the structure of the other), means that you really need to study the two in isolation to gain a full appreciation. Kind of like how Objective-C combined C and Smalltalk.

Anyhow, I'll eventually end up posting on the mailing list, but for now I'll let the current thread wind down naturally.

-- Added on Edit --

As I wrote, Alice does not yet implement SML's overloading on literals, so you have to use the explicit coercion I showed in my previous post.

Another Doh. Need to improve my reading comprension. Stumbled on the solution anyhow after reading some of the library docs.


I assume that this lack of overloading on the constants carries through in the pattern matching and the guards? That is, the following exhibits the same sort of behavior.

   fun fact 0 = 1
     | fact n = n * fact (n-1);
   fact(IntInf.fromInt(0));

Does 9999*9999 really overflow?

I did not think about it at first, but are you sure that 9999*9999 overflows in int? It shouldn't, and it definitely doesn't for me. If so, please file a bug report.

what's the default file extension for Alice (I'm just using .sml).
We use .aml throughout.
I'm kind of wondering whether basing the language on an extension to a current language will present barriers to entry. From the little I've worked with the extensions, I like what I see. But to get a real appreciation for the language, I can't help but think that being proficient in both SML and Oz

Actually, one of the motivations for Alice was to lower these barriers, as many people in the past had been put off by Oz and its syntax too early, or refrained from learning a whole new language just for some specific concepts they were interested in. By basing Alice on something standard we hope to avoid that and make the interesting stuff more obvious.

In principle, being proficient in Oz shouldn't be necessary at all to learn Alice, but of course there is a lack of material introducing the respective concepts with Alice itself, so that a detour through Oz might be necessary.

I assume that this lack of overloading on the constants carries through in the pattern matching and the guards?

Yes, absolutely. And by the way, the difficulty to easily transform overloaded pattern literals into something non-overloaded is precisely the reason that this kind of overloading has not been implemented yet.

Regarding fact, you can circumvent the problem by defining it this way:

fun fact 0 = IntInf.fromInt 1
| fact n = IntInf.fromInt n * fact (n-1)

This gives you fact : int -> IntInf.int, which is good enough because big integers do not make much sense as arguments anyway (would run out of memory). In other situations I do something along the lines of

val n0 = IntInf.fromInt 0
val n1 = IntInf.fromInt 1
fun fact n = if n = n0 then n1 else n * fact (n-n1)

[Note: Very strange, when I first named "n0" and "n1" in the example above "zero" and "one", my posting got rejected because of "suspicious content", provoked - as I found out with try&error - by the line declaring "one". Anybody knows the cause of this?]

Nope. That number squared.

The overflow occurs with 9999*9999*9999*9999. For some reason, CTM wants to throw out some really big numbers up front - the other one is Fact(100). Other than showing off Oz's number scaling feature, it's not the kind of numeric range that I'd typically encounter (never had the need for more than 32 bit integers, and this one goes into 54 bits (2^54).

For the sake of comparison, I seem to get the same sort of behavior in SML-NJ.

Phew...

OK, that makes perfect sense.

For the sake of comparison, I seem to get the same sort of behavior in SML-NJ.

Yes, both use (like most FPLs) a 31 bit int type by default.

Suspicious content [OT]

Very strange, when I first named "n0" and "n1" in the example above "zero" and "one", my posting got rejected because of "suspicious content", provoked - as I found out with try&error - by the line declaring "one". Anybody knows the cause of this?

I checked, and there's a regexp in the Drupal code which looks for certain patterns of assignment to certain names, including anything beginning with "on". This only applies within things that look like HTML blocks, but if you quote code with PRE or CODE tags, that condition is satisfied. I assume this is to prevent Javascript in messages hooking the event handlers, which have names like onClick.

There must be some other criteria, too, since I was able to insert the below (perhaps because of having administrator status, not sure):

val zero = IntInf.fromInt 0
val one = IntInf.fromInt 1
fun fact n = if n = zero then one else n * fact (n-one)

Pragmatic Languages

Trouble is I need languages I can actually use and benefit from.

I dream of a language that has the simplicity of Joy / Scheme and the "Objects All the Way Down" power and ease of use of Ruby, and the slenderness of C.

The more I program, the more I want a language that I can write programs to manipulate, analyze and write the programs I write.

Carter's Observation: Progress in Software developement in the Large is Blocked.

... by the fact that programming languages are designed purely as Human Machine Interfaces. Programs themselves, especially in very Large systems, are entities requiring exact visualization, analysis, manipulation and generation by programs.

From the view point of developing really Large Systems, Ruby/C++/Java/C# is an evolutionary dead end. Their semantics are inherently too complex for analysis and manipulation.

In a small academic system a clean architecture is a nice to have. In really big industrial programs, created by many developers working simultaneously, cleanly defined and enforced architectures are the only barrier between rococco and rubble.

Unfortunately current languages provide far too many semantic backdoors forcing us to use very unreliable people level processes to create the broad architectural partitionings. And once a rococco Big Ball of Mud has been created, our tools for untangling it are blunt indeed. (Believe me, I know, I untangle BBoM's for a living...)

Sounds like you want static typing?

The options would seem to be Ada/Eiffel on one side, or SML/Haskell on the other.

Orthogonal to static typing.

Static typing can be a nice cross check when you are doing a large refactoring like this, but it isn't what I'm talking about.

For example, the tool I use most when breaking a very large ball of mud apart is "grope". A wee ruby script that knows where every file in the system lives and allows me to do fast regex searches on _all_ of them.

What I really want is a tool that understands comment / non-comment, local, file scope and global scope symbols.

The other tool I use a lot is "nm", I pull out all the external defined and undefined symbols from the object files, construct a digraph and manipulate that.

Unfortunately that misses anything that is currently #ifdef'd out of view. But again, these tricks are one way. I can construct a view, I can work out where I want to cut, and then it is back to the text editor and perhaps emacs macros to help me make the cut.

Thread safety in C/C++ is an utter nightmare. The number of ways it can go wrong is amazing. I have constructed tools to find potential races, but still it only finds some, and even those require intensive hands on analysis to determine if they are real, and often require rearchitecting to fix.

I'm looking for a language that, like Joy is analyzable. That I can programmatically wade through megalines of code and make strong statements about them. With C/C++/Java/Ruby all I can do is heuristics. List potential trouble spots for further investigation.

Converting, compiler-like, a human readable form to a machine readable form is the least and weakest thing we need to do with programs. That has taken us to where we are today.

What we need now for large systems is languages that can be analyzed programmatically for a large number of other tasks....

  • Visualization.
  • Metrics
  • Enforcement of architectural policy decisions.
  • Discovering and cleaning the architecture of an evolved system.
  • Thread safety. (I hate threads, so many ways to get them wrong...)
  • Refactoring, both small and large.
  • "lint" like static analysis.
  • Automated simplification. We have had algebraic simplification for decades, and most code I see can really do with simplifying! (It is amazing how many bugs are revealed when you do so!)
  • Cosmetic improvements and layouts.
  • Aspect oriented program becomes trivial in a language that is easily analyzable.
  • Synchronization of interfaces between systems. (Common trick is to generate both sides from XML, wouldn't it be nicer to tweak interface on either side and be able to automagically reverse engineer it into the common representation.)

Factor?

Have you looked at Factor? (http://factor.sourceforge.net). It's got the joy of Joy, a bit of Scheme, and generic function based objects with a native code compiler (for x86).