I finally understand why I'm not allowed to use Lisp
groups.google.com
groups.google.com
And no, I'm not saying that it's ok for code to be overly complex or unmaintainable. I'm saying that your first impression of code is probably wrong and you need to understand it before you dismiss it.
Taking parser combinators as an example, if you write some code with parser combinators, simply document your choice as usual and include a hyperlink to http://en.wikipedia.org/wiki/Parser_combinator.
If I read your code and think this is overëngineered, it's up to me to show a better way, I can't simply wave it off as being too hard. That doesn't mean it gets a free pass, it could be that parser combinators for a custom DSL are too complex, perhaps the same problem could have been solved with JSON or something, but the default should be to accept it since it's a technique that is explained "in the literature."
On the other hand, if I roll my own complex code and I can't point to a reference for the technique, then it's up to me to make the case that it's simpler than the alternative. For an example, Benjamin Stein and I wrote #andand for Ruby. It's related to the maybe or option monads, but it doesn't take the standard form so I can't really document it with a hyperlink. The onus is on me to show that in Ruby, #andand is simpler than testing for null, using the null object pattern, or organizing code such that there are no unexpected nulls.
A more recent realization is that this goes both ways. If someone submits code to my project, I owe them the same thing: an honest attempt to understand their code even though it's easier to label it overly complex and go watch House.
It sounds like you're thinking more in terms of how you market a new project, which is a different problem that I'm far from being qualified to solve.
True.
For that reason alone, clever code is usually unmaintainable.
How does this follow logically from the first statement? And more importantly, what alternative do you suggest? Are you positing that for a given problem, there is always some alternative solution that is "less clever" and "more maintainable?"
If you've never seen folding and unfolding before, code that makes heavy use of "map," "each," "select," and so on looks clever. But in reality, it is simpler and less bug-prone than fooling around with for loops and off-by-one errors. To my eye, for loops are clever and unmaintainable.
Moving up the scale, what about recursive combinators?
https://github.com/raganwald/homoiconic/blob/master/2008-11-...
They look very clever. But then again, rolling your own recursion from scratch every time you need it makes the person reading your code do a lot of work to figure out what you're doing. Is it "clever" to separate the concerns of how to implement recursive algorithm from the code that does something recursively? Or is it clever to roll your own code every time?
WHat about parser combinators? Clever or not? How about rolling your own interpreter for a DSL? That's an official pattern from the GoF book. Can I do that and write maintainable code?
Anyhow, I'm saying the same thing over and over. What is "clever?" Making use of a language feature or algorithm or well-known practice that someone else hasn't seen before and is too lazy to learn? And what is the alternative? Greenspunning the same functionality in an under-specified, bug-prone one-off way?
Responsible developers write a lot less clever code because it means they feel obliged to comment the crap out of it and find the time to go through it with other team members.
Unfortunately there's a lot more clever code that only one person really gets. If you're too clever for your team, then quit slumming it and find a smarter team. You're going to be toxic to a team that isn't as clever as you are unless you assume the role of mentor and all of the responsibility that comes with it... and the required patience.
I don't dispute the existence of code that is unnecessarily clever, but I suggest that sometimes what appears to be "clever" for a given audience is in actuality the local optimum. Attempting to optimize it for readability without further study will worsen the code in some way, such as conflating concerns that have been carefully separated or introducing dependencies.
If "clever" is often necessary to avoid things like conflating concerns or introducing dependencies, I think this points us in the direction we need to take in improving programming languages. (Off the top of my head, this applies to both Ruby and Smalltalk.) Though, I've also observed that bolt-ons to programming languages to address these issues are often a bit too "clever" themselves. (Example: The original implementation of Objects in Perl.)
I agree!!!! As a rough rule of thumb, "horizontal" or "general purpose" libraries are a potential source of inspiration for language improvements.
In my own case, I think #andand is a terrible kludge. But if I were designing a new programming language, one question I would ask myself is, "How do I make this go away?"
I might add support for monads, Or maybe I would decide that null is a bad idea. I don't know, but I would certainly give it some thought.
// Here be gryphons and scabrous wyrmsAn entire application of "clever" for clever's sake is unmaintainable. This tricky sort of clever is sometimes exactly what's needed, but should be used sparingly, where it is most beneficial, and it should be well commented.
On the other hand, clever directed at the goal of readability and maintainability can be wonderfully maintainable. Clever for readability's sake should be throughout the whole application. Accomplishing this is an iterative task, ideally throughout the whole life of the application. This is one of the most important purposes of refactoring.
While it's much easier to brag about the 1st kind of clever and show it off to your coworkers, you'll benefit much more from the 2nd kind of clever.
A tip from my experience: Managerial emphasis on the 1st "clever" is sometimes accompanied by a culture of coder showmanship. Managerial emphasis on the 2nd kind of clever tends to be more focused on sustainable results.
You lose all credibility right there. C# is far from the worst language ever, and a pretty decent one among mainstream object oriented languages.
C# isn't half bad now, but back then, I agree it was fairly crummy.
Deleted comment
I would choose Python over C# for my own projects any day. However, I can't comprehend the senseless hatred that people have for C#. It is a nicer language than Java (imo) and it has very good performance. Furthermore, due to Mono, C# is no longer a closed platform.
Microsoft is not suing Google for patents on operating systems but instead pressures the handset manufacturers using Android.
Is there a guarantee that a customer can use Mono for commercial applications, without a shake down from Microsoft?
1. There is stuff covered by the ECMA/ISO standards. This is covered by the Microsoft Community Promise, which is legally binding. This stuff is safe from Microsoft.
2. There is a lot of .NET stuff that Microsoft has released under the Apache 2 license, which includes a patent pledge. If any of this stuff is implemented in Mono, it is safe.
3. There is stuff in .NET that is not covered by the standards, and has not been released by Microsoft under a license that includes a patent pledge. Mono has independent implementations of the interfaces of some of these things. There is no Microsoft patent pledge covering these parts, and Microsoft may have patents on their own implementations. These patents would cover specific methods used in the implementation, not the interface.
The risk from #3 is small. Most important, it is about the same as the risk if you use that functionality in a non-Mono system. For example, I believe that there is an XML parsing library included in category #3. If Microsoft has a patent covering some particular technique of implementing an XML parser, there is no reason to believe that the people who implemented Mono's XML handling are any more likely to have infringed it than the people who implemented Java's XML handling, or Ruby's XML handling, or Python's XML handling, and so on.
Also, most of the things in #3 are things specifically related to Windows programming, so you'll only find them in .NET programs that were written for Windows. If you are writing for Linux, you don't need those things. Even if you want your programs to run on both Windows and Linux, you can do that without using the category #3 stuff. For instance, instead of using WinForms, use GTK#.
If Microsoft did decide to sue someone over their patents that cover the category #3 items that aren't Windows-specific, it is doubtful they would go after Mono. Microsoft has done enough to support and encourage the development of Mono that they would have a big estoppel problem to surmount if they wanted to sue over Mono. It would make a lot more sense to sue over Java or Python, where they would not face the estoppel issues. Remember, as I noted earlier, the category #3 patents are as likely to be infringed by those as Mono.
And that is only thing that is remotely safe. All other is murky. But unfortunately, even that can be unsafe if Microsoft sell patents to CPTN (like they did with Novell patents) and let them sue even for ECMA parts.
Moreover, ECMA parts are unusable on their own. Eevery single mono app also depends on non-ECMA parts and Mono is always shipped with non-ECMA parts: http://www.the-source.com/2010/12/on-mono-packaging/
As for Estoppel, they didn't promise anything for non-ECMA. It doesn't work the way you think it works. In fact, they even promised to sue:
"If someone implemented a product that conforms to the specification, we believe we have a patent or one pending that’s essential to implementing the specification."
or
"The .NET framework contains the latest developer platform for the future, and it must be licensed like Windows. Subsets have gone about as far as they should go in the standards bodies, but we need a compact subset for phones and TVs. It was noted that we have to be careful because once the horses are out, they are out forever. At the right royalty, we can have discussions around technology beyond this."
I think that it's only natural that MS would target Mono if they felt it was a threat. Right now it is in their interest to support Mono because it introduces more people to C# and MS feels that this is good for the long-term health of their platforms. They are also able to iterate quickly enough that Mono (and Moonlight, the Mono-based Silverlight implementation) is always playing "catch-up" and the cool kids are all going to want to use the official implementations with the Cool New Stuff before it makes it into Mono two years later.
Mono developers can easily become Windows developers, and the likelihood of that happening is not that low if a given hacker falls on hard times and needs a job. This hacker will then buy Windows and Visual Studio (or get his company to buy them, either way works), probably multiple times. Hence, supporting Mono makes sense for now.
If Mono ever becomes a threat to Windows' dominance instead of a help, MS is going to go after it hard and try to kill it, just as they go after anything else perceived to threaten Windows or Office. Mono will be targeted because it makes things that used to be Windows-specific accessible on other platforms, destroying Microsoft's lock-in, leveling the playing field and making Microsoft an undesirable option. This is not something MS likes, and they will do everything possible, including patent suits if possible, to get Mono out of the way if they have to. They have already postured for it with their indemnification deals for Novell customers.
The same applies to WINE, although Microsoft for the moment just never mentions this because they're never asked about it, and they don't want people to find out about it and discover that they don't need Windows to run Windows applications. There is no benefit to promoting WINE like there is with promoting C# and other MS-centric languages.
However, there are too many developers who would riot (i.e. advise their boss not to go MS) if MS started playing too dirty.
Microsoft has tried to underhandedly support efforts to kill Linux (like buying tons of crap from SCO after its suit was filed), but they haven't gone "all out" yet. I don't think that means that they won't ever do that. Again, the deal with Novell is posturing; by offering customers the guarantee that they won't get sued for using Linux by MS, they are essentially saying they may sue non-customers as they feel appropriate.
Microsoft's cash cow has always been in the desktop -- desktop OS and office productivity suites. This is the market they'll fight to the death to protect. Bringing legal action against Linux now would only serve as a distraction and a big PR help to things like Ubuntu, exactly what MS doesn't want. They seem to understand the Streisand Effect. There's no point attacking an enemy that is struggling for traction.
* From the Mono Licensing FAQ [1]: "Microsoft has announced that the ECMA standards for C# and the CLI are covered under the Community Promise patent license. Basically a grant is given to anyone who want to implement those components for free and for any purpose."
* The Novell-Microsoft agreements provide further protection for companies that choose to use Mono. [1]
* Many companies are using Mono for commercial purposes. There is a list at http://www.mono-project.com/Companies_Using_Mono
* Notably, Linden Studios uses Mono for Second Life servers. (See http://wiki.secondlife.com/wiki/Mono)
http://techrights.org/2009/07/09/community-promise-sham/
and
http://www.fsf.org/news/2009-07-mscp-mono
and of Mono in general:
Email: miguel@gnome.org
Twitter: @migueldeicaza (http://twitter.com/#!/migueldeicaza)
That's where I stopped reading, but I'll say this: Nowhere in the FSF's critique of the MCP is it mentioned whether or not the promise itself is legally binding. From a bunch of people who are supposed to be legal experts. What does that tell you?
But, as far as that particular issue is concerned, as the techrights article points out,
"It may become legally binding ... if used as a challenge in court. But of course it does actually need to be tested in court /first/."
In any case, you might want to look up the legal term estoppel.
So please stop repeating estoppel meme, it is nonsense. Also, attacking all people who show the world truth about Mono shows you have no arguments. Reddit was spammed by Mono pushers who were impersonating other people.
In any case, sorry, but I'm not going to argue this issue with the likes of you. You may have a point somewhere, perhaps, but anyone associated with that blog has about as much credibility vis-a-vis Mono as Rush Limbaugh does when he talks about... well, anything. I bid you adieu sir. Good luck.
I don't know who "gnosis" is, first saw that nick.
Anyways, if you need to attack people and make this kind of nonsense, it means you have no arguments whatsoever, so you just do what rabid Mono pushers always do: character assassination and libeling of every critic, with heavy use of all kind of fallacies.
http://en.wikipedia.org/wiki/Association_fallacy http://en.wikipedia.org/wiki/Ad_hominem
C ya
Citing Boycott Novell about software (or about anything, actually) is about equivalent of citing your Astrologer in a science argument.
Why don't you actually address what they wrote in their article?
An ad Hominem attack would be calling you stupid for linking the biased source. That didn't happen.
I didn't even make an argument. I just linked to a few articles that criticized Microsoft's "Promise".
Did tsz address the substance of techrights' argument? No. He just smeared them by implying that merely citing an article by them would make me lose credibility.
That is a perfect example of an ad hominem.
Attacking me was more of a case of shooting the messenger.
If you do a Google site search on that blog you'll see that the term 'smear' is used endlessly and quite carelessly by the author. It's interesting to see that you use it in the same way - and like the author I don't think you understand very well what the term means. I sure hope "gnosis" isn't one of the various aliases the guy allegedly uses across the internet, including on Slashdot where he became a bit of a legend for maintaining dozens of them.
But, be that as it may, I'll just say that yesterday was the first day I've even heard of techrights, when I found their site through a google search.
And, honestly, I don't even care much about Mono. I'm just very suspicious of anything originating from Microsoft, and the techrights and FSF articles support these (well founded) suspicions.
Instead of dancing in circles, please look at the contact information I posted above. Miguel de Icaza is a good guy. I am certain he will answer any questions you might have.
...The danger is that Microsoft is probably planning to force all free C# implementations underground some day using software patents. ... This is a serious danger, and only fools would ignore it...
It seems as if they are passing off wild speculation as inevitable fact. What is to prevent MS from using its portfolio of patents on any given project? Is a free C# implementation infringing on more patents? The supporting links just looked like general anti-patent pages.
The author's qualm, coming from a Lisp POV, is most likely that if you are a consumer of C# 1.1 you can't just build C# 2.0 or 3.0 or 4.0 features. Using Lisp, he had access to everything that would eventually become C# features and then some, because if you want a fancy new language feature in Lisp you just add it. You don't have to touch the compiler (you write functions, macros, or a micro-compiler at the limit).
So there's some hyperbole there, but it's true that C# 2.0 or 1.1 was really not anything special and felt a lot like "Microsoft's Java" at the time.
C++ was mandated by the platform, but I spent a lot of time getting the STL and Boost up and running. The entire thing relied heavily on templates, including some of the more advanced meta-programming techniques. In each case the 'cleverness' was warranted as it greatly reduced the complexity and redundancy of the code.
My boss at the time raised concerns over how maintainable this all was. How we're junior programmers going to be able to work on it? Being all of 22 I naively responded "well, lets just hire people who can handle it."
Interestingly, that's exactly what we did. We were much more thorough in our hiring process precisely because we needed folks who could rise to the level of the code we had written.
It seems to me that people (and companies) tend to rise to the level of the expectations that you set. In this case, making the decision to use LISP means that you're consciously making the decision to hire the caliber of talent that can use lisp. That may be a good thing (it was in the case above for sure).
I suppose it really comes down to making sure that the complexity of the application warrants the use of the more advanced abstraction. A simple web-site for someone selling tractors might warrant a different ("easier") tool than something inherently more complex.
Meta: I wildly guess the HN post gets all the upvotes because initally people think that it will be about a google employee not allowed to use Lisp in google.
I am new to HN, but I think you should try to read posts before you vote them up. At least that is what I do, after clicking on the comments page. Often, HN comments are even more valuable than the article itself.
The article I read was about someone complaining about not being allowed to use all the features in the language selected for the project.
http://coding.derkeiler.com/Archive/Lisp/comp.lang.lisp/2006...
Which I think has been posted on HN before, Ron Garret's popped up a few times here, but it's still a great story.
Only managers would think that
int accum;
for(int i = 0; i < arr.length; i++){
accum += arr[i];
}
is more readable and maintainable than... arr.sum(x => x)
Oh look and even though I've written a million for loops depending on the language there is a bug because i didn't intialize accum.His code must have looked like this:
public delegate TResult Func<T,TResult>(T input);
public delegate TResult Func<T,U,TResult>(T inputA, U inputB);
public static TResult Fold<TAcc,T>(IEnumerable<T> collection, TAcc state, Func<TAcc,T,TAcc> f)
{
TAcc acc = state;
foreach(T item in collection)
{
acc = f(acc,item);
}
return acc;
}
//[...]
public int FunctionalMasturbation()
{
int totalWithdrawed = Fold<int,int>(0,_withdrawals,
delegate(int acc, int value)
{
return value+acc;
}
);
//...
}
This is an abomination. Right, for developers with a background in FP, than it's pretty clear what's going on, even if it looks like puke. But in 2007 you could hold a conference for all .net devs with knowledge of Functional Concepts in a telephone booth. arr.sum()Though technically it's not that "array of numbers" is a class, but that array of T implements the interface IEnumerable<T>, and Sum() is extension method defined for IEnumerable<int>
It's even in the standard libs, you don't have to build it. Documentation is here: http://msdn.microsoft.com/en-us/library/system.linq.enumerab...
1) strict typing, but with lots of constructs (e.g. inheritance, interfaces, generics, extension methods) to work around that strictness so that you can do what you want, if you understand the rules and syntax to get it to compile.
2) loose, "duck typing" so you just do what you want, but without compiler checking that it's possible, and with the posibility that it fails at runtime if the right method isn't found.
C# is in the first direction.
http://www.cplusplus.com/reference/std/valarray/valarray/sum...
> They follow where We the Blessed Gurus lead them. But
> this time it is to the slaughterhouse, because the
> world needs only fifty Lisp programmers to write All
> the Code.
Oh comp.lang.lisp. Why did I even bother to read the replies?Hell yeah. Overly-abstract code can be like using variable names x1 to x267 because it is more efficient to type. Time I spend grokking your code is time our website spends offline.
Ben says that smart people should also work with these languages because non-smart people might have to work with the code. I think that is actually what happens a lot in the industry. Smart people who know Lisp, Ruby, Python, etc. still end up coding in Java because that's the language everybody else knows.
What I don't like about this is that it's basically saying that people can't become good at programming. It's accepting that the majority of professional developpers can't learn to use languages like Lisp correctly or to understand a Lisp program that uses powerful abstractions.
Maybe the ones who really can't are not in the right business ?
But, consider the reverse - The C++ spec always seemed to as if the language designers were showing off - competing to add fatures that showed off how clever they were, without as much regard for the readability and maintainablity of the resulting code in the language. I don't think that strategy is optimal either.
Also, if you think only simple code can be done in C#, have a look at the Rx framework. C# as a language is suffering from a bit of bloat too, but not as bad as C++.
I've done a lot of work with Java (and some with C#) and most developers have a hard time even with original Java's scope rules.
So, if these languages want to be the COBOL of the future, they should keep it simple and dumb. Closures and Generics aren't for most people.
Or they could add some compiler directive for switching on advanced features.
Most people love dynamic typing, because they hate the static typing of languages like C++ or Java. Powerful languages also need a powerful type system, that the developer can fully express his intentions, with the aid of a compiler validating them. Mainstream languages should start looking at type systems of languages like Haskell.
For example, a few weeks ago I wanted to start writing a program that analyzed some spreadsheet files, spit back out some relevant information (including graphs), and then served this information up on some specified port. I initially wanted to write this program in Lisp so I began to look at available libraries. For the gui component, my first pick was Qt, for which Lisp actually has bindings. I spent about a week trying to get all the dependencies for it installed unsuccessfully. The documentation essentially says, "You need all these installed," and then gives you a bunch of links to their respective websites. All of the other details were missing.
Specifically, I could not install the smoke bindings for Qt. I searched for any guides or documentation and always found a git/svn repository. Once I had the files, I had no idea what to do with them; where they needed to go or how to compile them, etc. Raw .cpp and .h files that have dependencies do nothing in isolation. Furthermore, there was no support forum or any other place to ask for help.
Finally, I just gave up. It was too much work to just hack together what was supposed to be a fun weekend project. So I moved onto Python, which just worked. I'm sure I'm not the only one who has had such frustration.
Also, I would recommend that when you have problems like these you come ask about them on #lisp and #quicklisp on freenode.
There are many very helpful and knowledgeable people there. Often, they're the authors and maintainers of the very tools you're trying to use.
What is so hard about this??? //assume some sorta IEnumerable derivitive IEnumerable<foo> bar = new IEnumerable<foo>() { obj1, obj2, obj3, obj4, ...};
var accumulator = bar.TakeWhile(x => x.property == someValue);
but then I saw the .NET 2.0 timeframe.
But even with .NET 2 you had generics which makes things pretty easy. But then again, he/she is ranting so I should just ignore him/her.
It doesn't matter what language you are using, if you cant write something that is legible to solve the problem, think about it more.
Anyone else remember when you didn't have to log into google groups to look at a newsgroup thread?
I've seen this too many times. Smart developers write complex code, just because they can (and often it does make it shorter), but then mid- and junior-level developer struggle with it. So company has to spend more money on smarter developers.
Here's a relevant post by Linus:
http://thread.gmane.org/gmane.comp.version-control.git/57643...
If you're just adding up the elements of an array, no big deal use a simple loop. If you're iterating through three lists of potentially unequal length processing some triplets and skipping others and returning some data structure based on that iteration, a raw loop is going to be anything but simple and readable while using an abstraction like CL's LOOP is going to result in something very manageable.
To give an empirical example off the top of my head, look at any compiler code written in C. Iterating over flow graphs is a big PITA because they're nested heterogenous structures (a procedure has basic blocks which has instructions which has uses and defs). You iterate over them a lot and a lot of iterations end up being complex triply-nested affairs. Nearly all compilers written in C use some sort of abstraction to deal with this complexity. Eg: GCC has a bunch of macros of the form FOR_EACH_ that use the pre-processor.
You know, I can't help but be reminded of Harrison Bergeron when I read this. I'm waiting for the day when someone comes up with a handicap for programmers so that we can all write code with the same ability as the least intelligent and least experienced members of our teams.
Did it ever occur to you that there might be a method to smarter developers' madness? I mean, maybe they write code the way they do because, you know, they're smart and know something you don't?
Java? ;-)
In the majority of the cases however you deal with managers who lost understanding of anything but simple language constructs because all they did since becoming managers is management and no code development at all. At some point they start rejecting everything they don't understand. They justify their position by arguments of code clarity and maintainability. But they are misguided. To recognize readable and maintainable code you actually need to practice programming continually.
I dealt with such managers. They would tell me that a dozen of simple code lines are unreadable because they saw a new keyword they don't understand. But they would accept a hundred of code lines that do the same thing in which they can recognize all keywords. They wouldn't care about what the code actually does, nor they would care about what it takes to parse a hundred lines of spaghetti code.
It always fascinated me that some managers think they understand developing code better than developers they manage. I've had the best experience with managers that trust their developers to make decisions and the worst experience with managers that try to micromanage.
Huh?
> My manager looked at the code and asked "Who's going to maintain this? How will they understand it?" That's not the first time I've encountered these questions. I heard it when I used function pointers in C. I heard it when I used templates in C++.
So essentially the manager bans the use of basic language features because they have hired incompetent programmers who shouldn't be working in the languages before understanding them. How exactly did the manager "recognize the problem"? The problem isn't that people use languages like they are supposed to be used, it's that they have made bad hires, which is not the competent programmers fault.
* Whose idea was it to hire developers that are smarter than I am?
* Of course I told him not to use function pointers. You have to put programmers in their place from time to time. You know, show them who the boss really is.
* Function pointers? Are you serious? He could have put someone's eye out.
http://groups.google.com.nyud.net/group/comp.lang.lisp/brows...
or type the original link in to the form at:
This is made doubly painful by the incredibly obtuse error messages spat out by some compilers, like:
This expression has type ((int * int) * string * string * channel) list
but is here used with type ((int * int) * string * string * channel) list
or even more baroque and confusing monstrosities.Programming in OCaml made me feel like I'd need to take years of type theory classes in order to feel really comfortable in the language.
In comparison, programming in Lisp is a joy, and very easy.
But, in defense of the modern statically typed languages like OCaml and Haskell, I'll have to admit that once you've finished wrestling with the type system and actually gotten your program to compile, you've probably eliminated whole classes of bugs that might still exist in a similar dynamically typed language program. Not to mention that it will save you the writing a ton of unit tests.
error: conversion from std::_Rb_tree_const_iterator<std::pair<
const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >
to non-scalar type std::_Rb_tree_iterator<std::pair<
const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,
std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >
requestedAnyway just an aside
(Try comparing various languages here: http://shootout.alioth.debian.org/u32/benchmark.php?test=all... if you don't believe me)
Some dynamically typed languages can approach the speed of static languages, like Lisp, but they generally do that by introducing voluntary static typing hints, or having a JIT compiler introduce speculative code paths that guess the types coming in after some analysis.
That would be Common Lisp.
There was such a version of Smalltalk called Strongtalk, but it never got a community behind it.