Interesting programming language: F#
Has anyone coded in F# before? It looks fantastic, but since it was created by Microsoft I don’t expect a version I can use any time soon. but I like the way it describes and separates mutable and immutable data. I like the way it blends functional programming with object oriented stuff, and the way it is compatible with preexisting libraries written in other languages. I like the static type system and the type inference on top of it. It’s got a lot of cool things reminiscent of SML (or OCaml, presumably, if I knew it better) while at the same time keeping an imperative, object-oriented spirit about it.
I’m not wild about some of the syntax, particularly the way it’s hard to tell where the definition of a type ends. and that weird <- operator for storing mutable data. and the bizarre [|...|] delimiters of arrays. and the whole #light declaration and how that totally changes syntax (just pick one way or the other and stick with the decision). But so far my biggest complaint is the syntax, while everything else about F# seems pretty cool. Has anyone actually played around with F#? I'd be interested in hearing how it works in practice.
I’ve not used it (or OCaml) but would be happy to if the opportunity ever arose.
Using it on Linux or Mac OS X looks quite possible: http://www.strangelights.com/fsharp/wiki/default.aspx/FSharpWiki/MonoLinux.html
Ooh, thanks!
I’ve never used F#, but I’ve done a fair amount of non-trivial OCaml programming, so I can speak to that. The arrow operator for mutable data frees up “=” for comparison, which is nice. The strange syntax for arrays, etc. (at least in OCaml) takes some gettng used to, but it gets under your fingers pretty fast. Defining types shouldn’t be a big deal, because type inference should do all the work for you, or at least most of it.
Crazy directives that seriously modify the syntax are par for the course in functional languages: OCaml has p4, Haskell does it (see Control.Arrow, IIRC), and it’s built right into the foundations of lisp.
The meaningful differences between F# and OCaml are that F# has a multi-threaded GC (a big win if your program will be doing significant sharing between threads; a big loss otherwise), library support (the CLR kicks OCaml’s ass, no surprise) and development philosophy (INRIA considers OCaml pretty much “done”, but MS is still working on F#, so it won’t be stable for a while yet)
And, predictably, windows support for OCaml isn’t that good, and unix support for F# isn’t that good.
You make a good point about <- and =.
What I meant about types is that if you want to define an object-like thing with member functions and stuff, I don’t like the syntax distinguishing member functions from global functions (why not use some kind of traditional scoping mechanism like curly braces or Python’s colon/indentation? It would be way easier to read).
I agree with you that there are lots of languages where the syntax changes after certain things, but I still don’t think it’s a good idea. As evidence of this, I claim that no popular language (C++ in a normal setting without many preprocessor directives to ruin stuff, Java, Python, Perl, Javascript, LaTeX, C#, Fortran, PHP) does this, while the examples you cite are comparatively unpopular (the exception being Lisp, but I don’t know what you’re referencing there; Lisp has the simplest, most straightforward syntax I can imagine). If you want people to adopt your language, you need to give them one syntax.
As I recall, the object syntax in OCaml was messy; it’s probably better in F# (F# puts a bigger emphasis on objects), but I haven’t looked specifically.
What I’ve really found is that OCaml is an imperfect mix of functional and imperative styles; it’s in a different local optimum than, say, Python or C++, because it’s much better at functional than imperative. OCaml’s object syntax started as a fork of the CAML language, and then got patched back into the main branch (hence “Objective CAML”), so it feels a bit hack-y because it is.
The optimal place in my mind for OCaml and friends is for problems that are “mostly functional” (say, PLs classes, parsers, or FastSLAM) but are simplified by some imperative or object-oriented glue. This is my pet reason that Haskell hasn’t completely displaced everything else in the functional space: it’s much cleaner at the functional parts, but imperative gluing makes your head hurt.
I generally agree that providing many syntaxes is a bad plan, but there are some interesting counter-examples. Lisp’s macro system (“Code is a list. A list is a data structure. Therefore, code can easily modify code”) allows cool things like CLOS, which makes Lisp object-oriented, all in macros. There are OCaml syntax extensions that add things like list comprehensions and monads, too.
— Thinking out loud starts here.
I think there are two reasons that syntax extensions are pretty much unique to the functional languages: speed and researchers. Most (all?) “popular” languages are direct syntactic decendants of C, plus some Simula. C was designed to be a small language, so trying out new syntaxes wasn’t that hard; open up the source for gcc, poke it, go. On top of that, when cycles are expensive, significant syntactic transforms at compile- or run-time aren’t acceptable.
These days, C++ is such an amalgamation that changing the grammar by hand is unreasonable, so follow-on languages didn’t try to add that back in. (On the other hand, javascript functions know how to print their own source code; I don’t know if it’s writable, though)
So, I think PLs researchers want to be able to tweak their syntax easily even when they are writing a truly massive compiler (like Haskell’s); hence, syntactic transforms get built in. In OCaml’s case (and, I believe, F#’s and Haskell’s), the preprocessor gets partial access to the parser’s grammar, and then gets access to the AST after the code is read in; this isn’t true metaprogramming, but adding cute new syntax to see if it’s useful is now much easier. There’s plenty of syntactic sugar baked into the formal specification of languages; why not make it easy to add more?
I agree that the real result of all of this is to require that you add a page to the style guide that reads “THOUGH SHALT NOT USE SYNTACTIC TRANSFORMERS”, because it can make code deeply illegible to those who haven’t learned the pitfalls of the new trick.
(An aside: in principle, any language on a Von Neumann machine can introduce new syntax at runtime; of course, this is complicated by compiled languages, and totally destroys type-safety unless done very carefully, so most languages disallow it to some degree or other)
As I recall, the object syntax in OCaml was messy; it’s probably better in F# (F# puts a bigger emphasis on objects), but I haven’t looked specifically.
I haven’t looked into OCaml’s syntax, but the way to do it in F# requires separating out private data/functions from public ones, which seems like a good idea. However, the private stuff is enclosed in curly braces (ok idea) while public stuff is either enclosed in a ‘with…end’ block (ok idea on its own, but inconsistency between this and private data delimiters is bad) or just by indentation if you’re using #light (again, inconsistency is bad, and changing everything with #light is bad). On top of that, however, each member function must be preceded by the ‘member’ keyword and a dummy variable representing this/self (ex: ‘member x.Plus(y) = x.value + y’), and I think both the ‘member’ keyword and that initial ‘x’ are useless and redundant.
In case I come off as sounding too pessimistic here, I still think F# is a cool language; I’m just focusing on the dumb parts because if they weren’t dumb this would be an awesome language.
The optimal place in my mind for OCaml and friends is for problems that are “mostly functional” … but are simplified by some imperative or object-oriented glue.
Ah, I’m coming at this from the other side. I’d like a language that is mostly imperative and OO but with some functional bits when they’re useful (which is why I like Python so much). Yet at the same time I prefer the way most functional languages do static typing, type inference, pattern matching, etc (the anti-Python in this respect). So I guess I want a language that looks functional but still makes imperative programming easy.
To go one step further on your last point, I don’t think Von Neumann machines have anything to do with this: any Turing complete language will have a way to introduce new syntax at runtime, even ones that don’t run on Von Neumann machines. At the same time, something like a calculator, while a Von Neumann machine, probably can’t change its syntax at runtime.
I like your style commandment, and most languages (but not C++; stupid preprocessor) try to make these syntax modifications hard to do because it’s nigh unreadable. Languages should really be constructed for people to read/use (Perl being the obvious exception. :-P ). I think you’re right about researchers trying out new syntax tricks, but by the time I start coding in a language, any research on its syntax should be done, and the grammar should be finalized. but maybe that’s just my preference.