>We (BitKeeper folks) did our GUI interfaces in Tcl/Tk years ago because it meant we could have one gui person and get the same gui tools on Windows, Mac, Unix, and Linux.
>While some of us could switch from C to Tcl easily, our pointy-haired boss could not, he's mostly C and would lose about a half a day to get back into Tcl.
>Success was realized when one of our engineers, who is not a Little fan, fixed a bug in a patch that flew by in email without realizing it was Little instead of C
I'm surprised to see it getting some attention but happily so. Little is what I'd like C to evolve towards, there is a lot of useful (to me) stuff in the language.
I'll wander through the comments and reply where I can.
Jeff Hobbs from the tcl community helped as well. I have pictures of that group of people. Jeff helped a lot, he wanted this, I could say why but I don't want to speak for him.
Little is what I'd like C to be but those guys made it happen.
I'm amazed that Little got some traction, happy that it did for a moment, those guys deserve all the credit, I was a whiny dude wanted a more C like thing and they gave it to me.
On the other hand, we didn't make enough for everyone to retire if they wanted to. We had a github like offering and it's pretty clear that we should have put a bunch of money into that and open sourced BitKeeper.
All I can say is it is incredibly hard to make that choice when you have something that is paying the bills. I tried to get Sun to do it with the BSD based SunOS and they wouldn't. And even though I had that vision for Sun, when it was my livelihood, I couldn't see the path to doing so.
Shoulda, coulda, woulda, my biggest regret is not money, it is that Git is such an awful excuse for an SCM. It drives me nuts that the model is a tarball server. Even Linus has admitted to me that it's a crappy design. It does what he wants, but what he wants is not what the world should want.
It says a lot that we have a bk fast-export and we can incrementally run that and get idempotent results. As in go from BK to Git on an ongoing basis, have two people do it in parallel and they both get bit for bit identical results. If you try and go the other way, Git -> BK, if you do it in parallel you get different results because Git doesn't store enough information, so BK has to make up the missing bits.
Git has no file create|delete|rename history, it just guesses. That's my biggest regret, I wish Linus had copied that part.
It was good run, not many software companies get an 18 year run. I'm fine with it, would have liked to do more for my people.
Though, when we were shutting things down and I was bumming that I had not gotten retirement money for all of my people, one of them said something like "Dude, are you kidding me? My best friend barely knows his kids, he is out the door by 7am to fight Houston traffic and not home until close to 7pm. My commute is from my bedroom to my office down the hall. I've got to help my wife with the kids, I see the kids all day every day, my life is infinitely better than my friend's life and you gave that to me. You're fine."
I'm a wimp, I teared up a bit, that was the nicest thing he ever said to me. It's not just about money.
When we were still in business, each new SCM that came out, we'd hold our breath until we looked at it and said "No weave!"
For those who don't know, the SCCS weave is how your data is stored. Most people are used to something like RCS which is patch based. For the RCS trunk, the head is stored as plain text, the previous delta is a reverse patch against the head, lather, rinse, repeat. Branches are forward deltas, so if you want to get something on a branch, you start with the head, apply reverse deltas until you get to the branch point and then forward deltas until you get to the branch tip. Ask Dave Miller how much he loved working on a branch of gcc, spoiler, he hated it. With good reason.
SCCS has a weave that is not aware of branches at all, it only knows about deltas. So you can get 1.1 in exactly the same amount of time as it takes to get head, it is one read through all the data. bk annotate (git blame) is astonishingly fast.
And merges are by reference, no data is copied across a merge. Try that in a patch based system. How many of you have been burned because you merged in a branch full of code that someone else wrote, and on the trunk all the new data from the branch looks like you wrote it, so you get blamed when there is a bug in that code? That's because your brain dead system copied code from the branch to the trunk (Git does this as well, that's what the repack code is trying to "fix", it is deduping the copies).
Weaves are the schnizzle, any SCM system that doesn't use them today is so 1980.
2000.txt documents the first 2000 resyncs (think bk pull) of the kernel.
Avocet was what you got when you took all my perl code and handed it to the tools group and they rewrote it in C++ (which they later admitted was a horrible idea). The only thing of mine that they kept was smoosh.c and that was because not a single one of them had the chops to write that code (yeah, there was no love lost between me and the tools group).
BitKeeper is what Avocet could have been if Sun had not stopped me from doing any more work on NSElite (I was 1 guy who was coding circles around 8 tools people and they didn't like it). Shrug. C++ was just wrong, perl4 was just way faster to code in, and when I needed performance I coded in C. It's not my fault they picked the wrong way to go about things. (That, BTW, was the first time I ever personally saw that you really can have one guy who can do the work of 8, almost, but not quite a 10x programmer :-)
I think this is a super interesting project. It reminds me what Groovy is to Java, but backwards. Groovy is a “looser” version of Java that compiles Java. Little is a “stricter” version of TCL that compiles TCL.
One could release this "language" as a distribution of the inner language's compiler together with a wrapper (like C++ originally was to C), that, rather than adding features and compiling down, just analyzes the source file and errors out on use of forbidden syntax; or, if no forbidden syntax is used, just passes your code straight through to the inner compiler. A bit like a pre-commit-hook style checker, but a pre-compile-hook style checker.
Those commands effectively make any tcl function be able to operate as an f-expr (in old lisp parlance). Effectively (this is a simplification), an fexpr is a runtime macro, as opposed to the more traditional lispy compiletime macro.
Its what makes tcl feel more like a lisp-for-strings. Much of the truly horrible tcl code out there in the wild is from folks who try to use tcl as just another c-style scripting language.
Treat it more as a lisp, and it some of its inherent elegance shines through.
My $0.02 anyway ...
Compiles to Tcl byte codes
Interesting, I didn't even know there was such a thing.
Good to see <> and =~ live on.Perl has a lot of good ideas and things I find myself missing a lot when I use Python or JS (autovivification being probably #1) but IMO these one or two symbol magic variables would generally be improved if they were more descriptive, with maybe one exception for $_/@_.
Although I must admit reminiscing about this made me realize how much I miss Perl now that I'm forced to use Python for work.
Yet another horrible hack in Perl that for some reason is advocated for. Optional chaining / null propagation is a much, much better idea and shouldn’t have been any harder to implement.
My 3rd rewrite was very stylized and, I felt, maintainable. Which proved to be true as I had to fix bugs in it.
I did weird stuff like using $whatever as the index into the @whatever array.
But I digress. On the <>, Little has argv so you can do
int main(string argv[]) { int i; string buf; FILE f;
if (defined(argv[1]) && streq(argv[1], "-") && !defined(argv[2])) {
while (buf = <STDIN>) bputs(buf);
} else {
for (i = 1; defined(argv[i]); i++) {
if (defined(f = fopen(argv[i], "r")) {
while (buf = <f>) puts(buf);
fclose(f);
} else {
fprintf(stderr, "unable to open '%s'\n", argv[i]);
}
}
}
return (0);
}but why would you want to when all of that is
int main(string argv[]) { string buf;
while (buf = <>) puts(buf);
return (0);
}I mean, come on, that's cat(1) in 8 lines of code.
edit: I need to learn hacker markup. My code looks like crap.
http://mcvoy.com/lm/L/tcl/tests/langbench/
some results in the README. Perl holds up well. These are probably 10 years old though.
If you can make one language strongly typed, and one weakly typed, then you should be able to build one language which can do either/or, depending on a compiler flag. Then you simply decide before you start writing your code whether you want to write it weakly typed or strongly typed, and pass the correct compiler option.
Take that same idea, but add in every language's quirks, and just enable/disable them. Then we wouldn't need to constantly reinvent languages, because we'd have one that can do everything.
Otherwise we're going to keep re-writing the same damn thing for hundreds of years, and that just seems like such a pointless waste of effort.
https://thenewstack.io/larry-walls-quest-100-year-programmin...
set foo[i] = ""
In Little you can tell, we'll return undef (your clear "error" though in these languages it is a supported feature, not an error). So we support the auto expanding array but give you that extra bit of info that you are past the end.
Can someone explain what this does? Is this some Perl or Tcl thing? Unfortunately I've never used either :)
undef is both a function and a (non) value. It is the main reason Little never got pushed back into tcl, the tcl crowd hates the idea that there can be a value for a variable that is undefined. I found that very useful, for example, undef is the error return from any function. Just made sense to me, didn't make sense to the Tcl people.
Given the context, in little-lang, it appears to delete argv[1] and shift all of the right of that down, such that argv[2] becomes argv[1] and so on. That's so that the the "while (buf = <>)" construct used right below it doesn't process the regex as if it were a file to "grep" through.
In Perl, you would typically do it this way...
if (!defined(my $regex=shift(@ARGV))) {
die("usage: grep regexp [files]");
}I really wish more languages would adopt this syntactic sugar.
Personally, I would love a gcc --little dialect complete with a String type (and others) that is garbage collected and auto resized just like tcl/Little. With all the other Little goodness in there. Man, that would make C super pleasant. And it wouldn't be a new syntax like Go/Rust/whatever.
It had left me wondering what had caused it. There was a thread a few weeks ago where the old guard were describing an actual attempt to game the system, and I wondered if we were seeing a version of that being played out.
So Little looks a lot more like C than Pike does. And I like it that way. It's not for everyone but C programmers will probably like it.