Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
The Luon programming language (github.com/rochus-keller)
233 points by thunderbong on Dec 13, 2024 | hide | past | favorite | 119 comments


This is an impressive achievement, given there’s a whole language plus IDE. Kudos to the author. I couldn’t see any indication of what the author plans to use it for - I hope he can share more below?

I’m intrigued by the LeanQt library as well that the IDE uses (https://github.com/rochus-keller/LeanQt) too.


> what the author plans to use it for

Thanks. I e.g. re-implemented the Smalltalk-80 VM in Luon (see https://github.com/rochus-keller/Smalltalk/), and I consider implementing an Interlisp VM (see https://github.com/rochus-keller/gingko/) which uses LuaJIT, which was an important motivation to interrupt my Micron language project to implement Luon.


Amazing that you also managed to implement Smalltalk besides Oberon and Luon - all of them with IDEs!

Wow!

And by the way the startup speed of the IFE is just insane! it is actually faster than my simple text editor!


One of the most delightful places I’ve used Lua recently is in TurboLua, which gives the Lua VM access to all the necessary signals/pipes for writing high speed network applications, among other things. (https://turbo.readthedocs.io/en/latest/)

Do you see there being a way to make a TurboLuon with current specs?


I don't use TurboLua, but I think it's feasible to build a Luon adapter module if need be. The necessary 'extern' keyword is already part of the spec.


The Interlisp VM sounds awesome - I would love to see Notecards on Windows/Linux/Mac natively!


What do you mean by "natively"? Ahead of time compiled, or just working? If the latter, the present VM is already available on the mentioned systems. In my version, Gingko, I additionally removed a lot of outdated code to increase platform independence.


nice! do you feel like oberon has something that gives it an edge over more currently popular languages, or is it just a matter of personal preference?


Actually, I only use original Oberon when I'm migrating the old Oberon systems. My interest lies in finding out how I would have to modify original Oberon to be as productive as I am used to with e.g. C++, but still adhering to the goal of simplicity. My version, which I call Oberon+ (and to which Luon is quite similar, whereas Luon is even simpler), goes in this direction.

Actually an "edge over more currently popular languages" from my humble point of view is the goal and maintenance of simplicity. The term is subjective, but if you look at many of today's completely overloaded languages, it is intuitive to understand.


I have to ask, "why?" in the spirit of if you're smart enough to write an Oberon on top of Lua and then use that to write a Smalltalk VM then you're certainly smart enough to get around a complicated language and tolerate a lack of some simplicity.


Probably a similar reason why equations are simplified in mathematics. If something is not represented or implemented as simply as possible, there is obviously overhead or redundancy. In the sense of the lean philosophy, that would be waste.

Simple solutions are also less prone to errors and easier to modify and expand. This reduces the probability of errors and makes it easier to maintain and update the system.

Simplicity makes systems (and programming languages) easier for users to understand and use. This leads to greater user-friendliness and reduces the learning curve, resulting in a more positive user experience and, in turn, a lower error rate.

I'm sure there are many more reasons (apart from the obvious proof by authority, which is based on the statements of, for example, Einstein or Wirth).


Amazing project!

I get the appeal to write an IDE from scratch, especially if you are already an expert in writing GUIs with your framework of choice! I wonder if it would make more sense to spend that time writing a language server protocol daemon. That way, you could make your language available in any IDEs your users like that support LSP.


I'm usually working on older machines on which the IDE's supporting language servers would be much too slow or wouldn't work at all because of incompatibilities. I like lean tools with little dependencies. But there is a parser in moderate C++, so maybe someone else will implement such a daemon.


Could I ask why you find yourself working on older machines? Work? A fan of retro computing? Something else?


It's excellent hardware, I have many redundant copies and thus high availability, the system just works, I automatically take care of efficient implementation, and the generated executables have high probability to work on all newer Linux systems. And I'm too old to always chase for the new new version.


Optimizing your code for slow machines is a really great thing. I wish more people would do it. If your code runs well on a slow computer then it'll run well on anything better too. A lot of code these days only runs "well" on very fast computers...


I mainly develop TXR on a refurbished Intel box with a CPU that's like from around 2009 or something. It takes at least three times longer to rebuild everything than on modern machines. (It does have 32 gigs of RAM which is good for multiple virtual machines.) In fact I have one Dell box that was a server in a startup company that shut down in 2010. And that box builds the code significantly faster.


Even VIM has support for LSP in extensions, I'm sure there's some lightweight LSP supporting editors out there.


I am actually glad that this person developed the IDE. Please download the IDE and try it. It is exceptionally fast. When I compare the speed with that of IDEs like Visual Studio Code etc, the difference is night and day.


If you want to hear the music, which I had in my head when I implemented Luon, here is the link: http://rochus-keller.ch/?p=1317 ;-)


Wow! That’s impressive. The video at the top of your post really helped me understand the coordination involved. Thank you for sharing.

I imagine you’ve been playing music most of your life. How long did it take you to bring all of this together and start “one man band” improvising?


Thanks. I actually started playing the piano in 1975. But only in the early 2000 I started to play bass on a pedal board. In 2010 I made my first experiments with playing the drums instead of the bass on the pedal board (http://rochus-keller.ch/?p=317). In 2014 I had a dedicated setup simulating a big band and played together with other musicians (e.g. http://rochus-keller.ch/?p=962). In 2022 I bought a Mac mini M1 and since enjoy the excellent sound quality of the new plugin generations. Only this year I managed to play the ride cymble as a real drummer would do it.


> locals can no longer be used before declaration

There's a lot I like about Lua but it so happens that a few days ago I spent longer than I'd like to admit debugging a trivial typo for Advent of Code day 5 that would have been caught by this.

Wondering if Luon will also prohibit or at least warn about storing nil in a table.


Luon doesn't directly support tables, but instead supports records, arrays and hashmaps (which internally use tables). Since it's statically typed you can only store nil to a field or element if it is of a structured type.


What's a structured type? Something that has fields or elements?


Records, arrays and hashmaps are structured types; in contrast to original Oberon, Luon has no pointer type, but reference semantics instead.


So Luon has reference types and value types, and reference types are always nullable?


Yes, but value types are only basic types. Structured types only have reference semantics and are nil by default.


This looks really good. It seems to fix all the warts and moles in Lua that used to exasperate me and adds type-safety which is a huge enhancement.

Replacing the 'everything is a table' with records, arrays and hashmaps is also a thoughtful improvement IMO.

Just confirming one point to make sure I understand the licensing implications correctly. Since the compiler transpiles to LuaJIT, and since that's just data, using output of the (GPL v2/v3 licensed) Luon compiler (i.e. the LuaJIT output) in a commercial/closed source project without divulging the source of said project should be fully kosher right?

Am guessing the answer is most likely in the affirmative but just making sure.


Yes, what the compiler generates (LuaJIT bytecode in the present case) is not affected by the license which applies to the compiler. Usually, the runtime libraries which the generated code automatically depends on, are of bigger concern. Luon offers a GPL exception for the runtime code, as well as an LGPL or MPL license. So you can essentially use the runtime code for any purpose.


Luon looks mostly like Oberon and not so much like Lua, it's not obvious which of the Lua features it incorporated. It didn't seem to have coroutines, for example.

But I am glad that it went with Oberon's 0-based array indices, as opposed to Lua's 1-based table indices.

https://github.com/rochus-keller/Luon/blob/master/specificat...


> Luon looks mostly like Oberon and not so much like Lua

Luon can indeed look similar to Oberon if you use upper-case keywords and semicolons, but there is not need for this. Both - Lua and Luon - have much in common with Modula-2 (given lower-case keywords). There are many elements in Luon which are pretty similar to Lua, e.g. constructors, pcall, most control and loop statements. But there are also significant differences of course, because Luon is a statically typed language and Lua isn't.


Modula-2 – a blast from my past. Back in the ‘80s I used it to implement a prototype distributed OS (as designed by a team at JPL) on VAXen. Logitech (!) had a really nice VAX compiler back then. One of the most productive 6-month stretches of my career. Luon looks like an answer to my unspoken prayers. Thank you!


Welcome. Actually we learned Modula-2 when I was at ETH in the eighties, and I had even a job at DEC Switzerland for some time where I had to develop course ware for the VAX Modula-2 compiler, but it was from DEC as far as I remember (probably this one: https://github.com/GunterMueller/DEC-Modula-2). Luon is actually a subset of my Oberon+ language; maybe you want to have a look at it: https://oberon-lang.github.io/.


I love Oberon: spent a few years mainly working in Oberon Microsystems Oberon/F aka Component Pascal, another beautiful language.


Don't all of Wirth's languages let you use any ordinal as the array index? At leat in Pascal you can declare an integer subtype, say 7..17 and use that as the type of the index of an array. Then the first element is item 7.

The point being that both the start at 0 and start at 1 camps can have it their own way.


> Don't all of Wirth's languages let you use any ordinal as the array index?

In Oberon, Wirth kicked out everything to the bare minimum, including subrange types. Array indices in Oberon start with 0.


>Don't all of Wirth's languages let you use any ordinal as the array index? At leat in Pascal you can declare an integer subtype, say 7..17 and use that as the type of the index of an array. Then the first element is item 7.

Can confirm that about Pascal, since I had used it a lot earlier.

Don't know about the other Wirth languages.

>The point being that both the start at 0 and start at 1 camps can have it their own way.

Yes, but that is not the only point. Another reason, and maybe the more important one, is that having such custom array index ranges, can more naturally fit the problem domain. In fact you can even use user defined types for the ranges, e.g. so you can define an array with Sunday to Saturday as the indices and the values of (the equivalent of) an enum representing 1) weekdays and 2) weekends, as the corresponding values.

Then your code involving days and weekdays and weekends, will read more naturally, so will be easier to both read and maintain. And you only have to do those custom definitions once, up front, so it is not much extra work for the benefit gained.


I have a really hard time understanding why people like 0 based indexes. They are a relic of C style arrays that are based on and interchangeable with pointers which use offsets that are naturally 0 based. Use in later languages gives us endless off-by-1 issues and rise to "for 0 to count/len/num - 1" or even better range syntax that is start inclusive BUT end exclusive. It is a horrible cludge just to support 1970s language perfomace optimization. Arrays should start and end at whatever start index is required, not at offset 0 of pointer to fist element of array.


Hang on. Off by one issues are the argument frequently given in favour of zero-based indices, not the other way around. For example, let's iterate through items placing them in 3 different groups;

JS:

    for (let i = 0; i < items.length; i++) {
        groups[i % 3].push(items[i]);
    }
Lua:

    for i = 1, #items do
        table.insert(groups[((i - 1) % 3) + 1], items[i])
    end
Don't get me wrong. I like Lua, I've made my own IDE for it, https://plugins.jetbrains.com/plugin/14698-luanalysis, but this is definitely not an argument in favour of 1-based indices.


Off by one issues are also an argument given in favour of no indexing.

    groups=new Array(3).fill([])
    items.reduce(function(a,x,y){y=a.shift();y.push(x);a.push(y);return a},groups)
Array languages typically have a reshaping operator so that you can just do something like:

    groups:3 0N#items
Does that seem so strange? 0N is just null. numpy has ...reshape([3,-1]) which wouldn't be so bad in a hypothetical numjs or numlu; I think null is better, so surely this would be nice:

    groups = table.reshape(items,{3,nil})   -- numlu?
    groups = items.reshape([3,null])        // numjs?
Such a function could hide an ugly iteration if it were performant to do so. No reason for the programmer to see it every day. Working at rank is better.

On the other hand, Erlang is also 1-based, and there's no numerl I know of, so I might write:

    f(N,Items) -> f_(erlang:make_tuple(N,[]),Items,0,N).
    f_(Groups,[],_,_N) -> Groups;
    f_(G,Items,0,N) -> f_(G,Items,N,N);
    f_(G,[X|XS],I,N) -> f_(setelement(I,G,X),XS,I-1,N).
I don't think that's too bad either, and it seems straightforward to translate to lua. Working backwards maybe makes the 1-based indexing a little more natural.

    n = 0
    for i = 1,#items do
      if n < 1 then n = #groups end
      table.insert(groups[n],items[i])
      n = n - 1
    end
Does that seem right? I don't program in lua very much these days, but the ugly thing to me is the for-loop and how much typing it is (a complaint I also have about Erlang), not the one-based nature of the index I have in exactly one place in the program.

The cool thing about one-based indexes is that 0 meaningfully represents the position before the first element or not-an-element. If you use zero-based indexes, you're forced to either use -1 which precludes its use for referring to the end of the list, or null which isn't great for complicated reasons. There are other mathematical reasons for preferring 1-based indexes, but I don't think they're as cool as that.


Yes, that is what is so frustrating about this argument every single time it comes up, because both sides in the debate can be equally false, or equally true, and its really only a convention and awareness issue, not a language fault.

It’s such a binary, polarizing issue too, because .. here we are again as always, discussing reasons to love/hate Lua for its [0-,non-0] based capabilities/braindeadednesses..

In any case, I for one will be kicking some Luon tires soon, as this looks to be a delightful way to write code .. and if I can get something like TurboLua going on in TurboLuon, I’ll also be quite chuffed ..


Your second example subtracts and adds 1 nearly arbitrarily, which wouldn't be needed if the convention of the 0-index wasn't so widespread.


You need the first three elements to go into the first group, the next three to go into the second group, and so on. How would you write it?


That’s not what that loop does, it puts one item into each next group and loops back over the groups after every three items. Really it ought to be a by-three stepped loop over items, inserting each into each group inline:

groups[1], groups[2], groups[3] = items[i], items[i+1], items[i+2]

If the group count is dynamic, you can just loop over groups instead, and then step through items by #groups, inserting.


If it is dynamic one of the loops will also suffer from an off-by-one issue. You can't add 1-based indices together like you can zero-based indices.

It's also worth noting your solution exhibits similar off-by-one behaviour. The left hand side constants (integer values) do not match the right. It's error prone.


  >You can't add 1-based indices together like you can zero-based indices.
I think you are right but I am unable to articulate why. But I think 0 based indexes are able to fruitfully capture "going nowhere" iteratively than 1 based indexes, which do require a decrement in that circumstance.


sorry, where is the off by one? the code offered is of course only a solution for the fixed-size groups


Fair enough, for some reason I thought it was i/3 and not i%3. Still, I think the point stands.


why not just iterate in steps of three over items for each next group? seems a bit contrived.


Because it's a simplified example to demonstrate the problem. If you do as you've described you need three separate assignments. What happens when the number of groups is dynamic? Nested loop? This is suddenly getting a lot more complicated.


Yes, that’s what I was saying:

for each group:

for i in steps of #groups:

assign item to this group

I think that’s a lot easier to comprehend than the modulus trick


For a lot of people the modulo approach isn't a "trick", it's just the intuitive way to split items into residue classes. And it's likely a little more cache-efficient.


well clearly your comment is meant to demonstrate that it’s a clumsy approach in a 1-indexed syntax, so perhaps a different technique would be more facile here… such as a counting method :)


Having done fairly extensive parsing work in Lua and Julia on the one hand (one-based), and Python, Javascript, and Zig on the other (zero-based), the zero-based semiopen standard makes intervals dramatically easier to calculate and work with. It's really the semiopen intervals which make this the case, but as the Word of Dijkstra makes clear, zero-basis comes along for the ride, to combine semiopen intervals with a one-basis is perverse.

Naturally it's true that for collections and naïve indexing, 1-based is more natural. But those are rare places for bugs to occur, while interval calculations are a frequent place for them to occur.

Clearly I'm far from allergic to the other standard, but I come down on the side of the zero basis for that reason.


I have a really hard time understanding why people like 1-based indexes! 0 is the smallest unsigned integer in every programming language I know of that supports the concept of unsigned integer. Why shouldn’t an array at the smallest possible index correspond to the beginning of the array?

It’s also very natural to think of arr[i] as “i steps past the beginning of arr”. With one-based indexing arr[i] has no natural interpretation that I know of. It’s “i-1 (for some reason) steps past the beginning of arr”. The only reason I can think of to prefer that extra -1 in your formula is just because human languages (at least the ones I know of) work this way — the 42nd element of a sequence, in normal colloquial English, means the one 41 steps past the beginning. But I’m not sure if there is any logical justification for that.

I also, despite being American, find the convention used in many countries of numbering building floors starting with zero to be more logical. I’m on the third floor, how many stories up did I travel to get here? Three.


> Why shouldn’t an array at the smallest possible index correspond to the beginning of the array?

Because then there is no good way to refer to the index before that point: You are stuck using -1 (which means you can't use it to refer to the end of the array), or null (which isn't great either).

> every programming language I know of that supports the concept of unsigned integer

Surely you know Python which uses a signed integer as an index into their arrays: list[-1] is the last element of a list. If they only used one-based indexing then list[1] would be the first and that would be nicely symmetrical. It would also mean that list[i-1] would NEVER refer to a value after ‹i› eliminating a whole class of bugs.

> It’s also very natural to think of arr[i] as “i steps past the beginning of arr.”

I think it's more natural to think of arr[i] as “the ‹i›th element of arr” because it doesn't require explaining what a step is or what the beginning is.

The exact value of ‹i› matters very little until you try to manipulate it: Starting array indexes at one and using signed indexes instead of unsigned means less manipulation overall.

> find the convention used in many countries of numbering building floors starting with zero to be more logical

In Europe, we typically mark the ground-floor as floor-zero, but there are often floors below it just as there are often floors above it, so the floors might be numbered "from" -2 for example in a building with two below-ground floors. None of this has anything to do with arrays, it's just using things like "LG" or "B" for "lower ground" or "basement" don't translate very well to the many different languages used in Europe.

The software in the elevator absolutely doesn't "start" its array of sense-switches in the middle (at zero).


> In Europe, we typically mark the ground-floor as floor-zero,

_Western_ Europe. Eastern Europe prefers 1-based numbering. The reason, typically assumed, is that thermal isolation, required due to colder winters, causes at least one stair segment between entrance and the sequentially first floor.


Python might have used array[~0] instead, where ~ is required, to indicate end-of-list 0-based indexing.

But I guess they wanted to iterate from the end back [-1] to the start [0], making it easy to implement a rotating buffer.


> Python might have used array[~0] instead

This is what was once added to C#: arr[^idx], when this ^idx is mapped to a special object, typically optimized then out. arr[^0] means the last element.


[^n] indexing is mapped to an 'Index' struct by Roslyn which can then be applied to any array or list-shaped type (it either has to expose Index-accepting indexer, or a plain integer-based indexer and Count or Length property. There really isn't much to optimize away besides the bounds check since there are no object allocations involved.

A similar approach also works for slicing the types with range operator e.g. span[start..end].


> I think it's more natural to think of arr[i] as “the ‹i›th element of arr” because it doesn't require explaining what a step is or what the beginning is.

Yes, but if you will eventually need to do steps on your array, you better opt for the framework that handles them better. I agree, that if your only task is to name them, then 1 based indexing makes more sense: you do that since diapers, and you do that with less errors.


In India too, the floor at the ground level is called the ground floor (probably that is where the name came from), the one above it is called the first floor, and so on. The convention is probably from British colonial times.

Also LED floor numbers in lifts (elevators) in India start from 0 for the ground floor, as do the buttons that you press to go to specific floors.

Also, Ground Zero.

https://en.m.wikipedia.org/wiki/World_Trade_Center_site

https://en.m.wikipedia.org/wiki/Hypocenter#


> I also, despite being American, find the convention used in many countries of numbering building floors starting with zero to be more logical. I’m on the third floor, how many stories up did I travel to get here? Three.

Alternatively the ground floor is the first floor because it’s the first floor you arrived at when you entered the building.

The same point of view applies to 1-based indexing.

That said I prefer 0-based in programming and 1-based in buildings.


I never understood why they didn't picture the building, with the buttons and the room/apartment numbers at each floor... That would make all conventions clear. Going negative would be obvious, and just indicate which floor the elevator is at with LED's of backlighting.

They never heard of making a UI, and just slapped buttons.


> They never heard of making a UI, and just slapped buttons.

I suspect that floor numbering predates lifts (elevators) by centuries.

Stairs are ancient.

I mean, zero itself is a non-obvious concept. Its invention is a matter of historical record:

https://www.open.ac.uk/blogs/MathEd/index.php/2022/08/25/the...

... and we still use counting systems which predate the invention of zero, such as Roman numerals.


> find the convention used in many countries of numbering building floors starting with zero to be more logical.

Ukrainian here. Multi-floor buildings always have at least one stair section to first floor due to need of thermal basement isolation. (I guess this is not pertaining to Western Europe due to more clement winters.) And, yep, it is called "first" floor. Using zero number is rare but possible (in this case it is called "tsokolny" floor) if a real "basement floor" is present, but in this case still 1-based numbering is preferred.


I'd argue that 1-based indexing is the "natural interpretation". Mathematics is inherently 1-based, and it isn't surprising that languages designed to do mathematics like R, Matlab, Mathematica, Julia all do 1-based arrays because that makes modeling paper mathematics in programs easier.


Sequences in math start with 1 by convention, not for any fundamental logical reason. It’s a reach to say that math is “inherently 1-based”.


I don't think it is.

Mathematics as a discipline predates the invention of the digit zero. The concept sure, but the notation and building positional representations around it is around 2000 years old.

https://en.wikipedia.org/wiki/0#History


> [0-based indexes] are a relic of C style arrays

I don't think this is true. They exist in other disciplines (maths for instance) that have no relationship with C or other programming languages from the 1970s.

> for 0 to count/len/num - 1

I will counter saying that such a for...to syntax is a relic of BASIC.

> or even better range syntax that is start inclusive BUT end exclusive

I know that your "better" is sarcastic, but I actually find left-inclusive+right-exclusive ranges fantastic. They allow perfect partitioning, easy calculation of lenght, etc.

> Arrays should start and end at whatever start index is required

I agree. An accommodating language would let you define both lower and upper bounds of an array, instead of its size.


IIRC some BASIC(s) I've used in the past had a statement called:

OPTION BASE 1

or something like that, to change the starting index to 1.


APL has ⎕IO←0 or ⎕IO←1 to change the starting index (only between 0 or 1, not arbitrarily). It doesn't apply system-wide so different code blocks/files/modules(?) can set or reset it, and portable code has to either set it or adjust for it.

APLCast podcast has an episode mentioning it where they all seem to agree that this is the worst of all worlds, makes sharing code and integrating codebases needlessly bug-prone, and the language picking a single indexing and sticking to it would have been better, even if the choice hadn't gone the way they would have personally chosen.


Interesting. Never used APL, though I tried J a little a few times.

Yes, that seems bug prone, somewhat like having to have a config file per module.


There are 360 degrees in a circle, and the first entry is 0 degrees. The first time element of a day is 0:00:00(and enough 0s to satisfy whatever resolution you require). These were not established in the 1970s, and somehow pretty much everyone understands and works quite well with these systems.


> There are 360 degrees in a circle, and the first entry is 0 degrees.

To be pedantic, "first" is associated with 1. And a circle does not have a "first" entry, whatever you mean by entry. I think what you're trying to say is that a circle is a continuous arc going from 0 to 360 degrees, but you should recognize that the "starting point" is arbitrary, any point will do, so there isn't really a "first", and that this is not the same as counting because counting is done with natural numbers, which are non-continuous. The problem of 0 VS 1 makes sense only in counting exactly because it's subjective whether you prefer to count from 0 or from 1. Because zero is the absence of anything, I find it hard to start counting from 0 (when you do, your "first" item is actually your zeroth item, and the next item would be the "first"??!), to be honest, despite being completely familiar with doing so since I've used 0-index programming languages my whole life.


If you cut up a circle into n slices (maybe you're drawing a diagram on screen), it's vastly more helpful to think of one of the segments as segment 0 because then the start angle of every segment is index*360/n and the two segments whose border is at your initial angle are the first and last. If you start counting segments at 1, your “first” segment would be some way into the circle, and the two segments whose border is at your initial angle would be the last and the second-last.


Don't you see that what you're talking about is a range, not counting?? A range indeed starts at a zero point because if you don't have another point, you just have an empty range: and that's the equivalent of a zero range. When you have two points in a range, then the "first" point ends up being zero, that's correct, because it's being treated as the beginning of it. An "origin" is always associated with zero. It's perhaps incorrect to use the word "first" in this case exactly because it "breaks" how ordinals actually work (i.e. 1=first, 2=second, etc.). A better word is the "initial" point of a range, and the "other" point is the "final" point. Each segment you consider will be a pair [initial, final]. Here's where your mistake comes in: you assume that you can just take each segment and assign it a single number, but instead of using the ordinal numbers which start from 1, you decided to, arbitrarily, take the initial point of the range as your number instead, which is where the zero comes from. Notice that the zero you chose comes from the pair [initial, final], but the zero only makes sense when it's in a pair (alone, zero means the absence of something, i.e. there's no range... I thought that concept was well understood at least by fellow programmers, but apparently not).


I really don't see how your comment helps reduce complexity. It seems to me that you're introducing a new concept, “ranges”, just to maintain traditional 1-based ordinals, instead of realizing that when you count from 0, counting and ranges simply become the same thing and you don't need such a distinction.


No, "first" infers a sequence and is associated with the beginning of that sequence. In the case of a relative heading, the existing heading is 0 degrees. Any change is relative to that origin point. Zero is also not the absence of anything, that would more properly be considered a NULL or NaN.


You're wrong.


Also, how many years old are you when you're born? Zero. (at least in mainstream Western culture).


Some countries consider the 1st floor to be the ground floor, others consider the 1st floor to be the floor above the ground floor, which the formerly mentioned countries consider the 2nd floor… I think 0/1-based indexing is more subjective than simply being a “relic of C” or a “horrible kludge” :P


I've been in the US for over a decade and it still occasionally makes me double-take when a room numbered 1xx is on the ground floor


Here’s the ultimate authority on why computer languages should count from zero:

<https://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF>


I find that argument to be written in a terse "mathy" style that makes it a bit hard to follow. So let me try to restate it in more concrete "programmy" terms.

To iterate over an array with "len" elements, it’s most elegant if “len” appears as a loop bound, rather than "len+1" or "len-1". Thus, in 0-based languages we use half-open ranges, whereas in 1-based languages we use closed ranges:

  // real C
  for (int i = 0; i < len; ++i)
      process(array[i]);


  // C-like language with 1-based indexing
  for (int i = 1; i <= len; ++i)
      process(array[i]);
But the second is inelegant when len is zero, because 0 isn’t a valid index at all, so it’s weird for it to appear as a bound.


Yeah, I disagree with Dijkstra on this. And many other things.


Dijkstra, being one of a handful of luminaries in the field of computer science – indeed, he can be said to have created the field itself – can be (provisionally) taken at his word when he claims something. You, on the other hand, being an anonymous user on a discussion forum, will have to present some pretty strong arguments for the rest of us to take you seriously. Your mere disagreement counts for approximately nothing.


>They are a relic of C style arrays

Doesn't it predate that by a good amount? I would think it is a relic of the EEs who built the digital world, those early languages show a great deal more relation to the bare metal than modern languages. Creating an array whose index starts at 1 just doesn't make sense from the discrete logic point of view, you are either wasting an element or adding in an extra step.

But in this day and age how can a language not have ⎕IO ← 0?


I honestly think that most of the problem arises from the fact that we just culturally start counting at 1 when talking about everyday things. As it stands, we're all used to it that way, and then computers come along and show us that counting from 0 is often more useful. So we adjust, but only for computer programming purposes.

If our species had established counting from 0 as the norm right away (element #n is the one that has n elements before it; you think of the number as the number of steps you have to move away from the starting point), then I suspect the reverse would not be true: I don't think anyone would find a situation in which counting from 1 is so much more convenient that it's worth going against the grain of established norm.

So in summary, I think we only think of counting from 1 as natural because it's in our culture. And it's in our culture because ancient superstitious humans had an irrational problem with the number 0.


I absolutely agree with you. People want to start with 1 because English (and presumably a lot of other languages) happen to use the word "first" to refer to the first element of a sequence, and not for any logical reason independent of arbitrary human language.


Slam! Now this guy really knows how to hate on a zero based index!


It's funny that nearly half of all comments are below your comment. The topic seems to unsettle people much more than a new programming language. This is also another example of how a downvote button is primarily misused in practice.

> Arrays should start and end at whatever start index is required

That's what you were indeed able to do with Pascal and also Modula-2, but with Oberon, Wirth came to the conclusion, that other index ranges than 0..n-1 were not needed. In his 1988 paper "From Modula to Oberon" he considers it "inessential" and providing "hardly any additional expressive power", but causing "a hidden computational effort that is incommensurate with the supposed gain in convenience". I think, in the end, it is in the eye of the beholder.


Dijkstra said that 0 was better for reasons.


Is this purely a personal project, or is it supposed to be used by others? You have made so many languages in the Oberon family (great job keeping the traditions alive, by the way), it's hard to know whether they are just a personal experimentation or you are expecting others to use them too.


This is not actually a contradicion, and the audience will decide whether the language will be used more widely. It's not my first priority, but there's nothing against it either. What you call "tradition" applies to my experiments with the Oberon Systems and the backward compatibility with their source code (for practical reasons, otherwise I would not be able to compile them), but my interest is actually in the language adapted for today's meaning of simplicity, which I call Oberon+ (or Luon, or Micron), and which would definitely have the potential for further adaptation if you look at what kinds of new languages are popular at the moment.


It's nice when a project can find such a simple pronouncable name that is also meaningful.


I keep thinking it's called Luberon, which probably isn't helpful.



I confess I was worried, until I read the name explanation, that it was named after Lululemon's marketing term for its preferred elastane/cotton blend


Funny; it's actually surprisingly hard to find information; but Perplexity told me, that Lululemon's Luon is a material which has great flexibility and maintains its shape over time, wicking away sweat, and good coverage; all good features for my programming language ;-)


I would have preferred a typescript equivalent for Lua. This is a bit too radical for a casual Lua user.




Why use a language with Oberon syntax, when there's Teal, which has Lua syntax and a TypeScript to Lua compiler?


Because Pascal/Modula/Oberon is the one true language. TypeScript? Blasphemy!


What's Oberon's unique selling point?


Quite high abstraction for its simplicity, quick to learn, strongly typed, garbage collected before it was cool (same as Module 3) and yet a system programming language (Oberon OS).

You could argue that Wirth overdid it a bit with the simplicity vs. Comfort features but that's probably also dependent on your preferences and the problem you want to solve.

There are a few languages where you regret that they did not win in favour of C++ and Oberon is one of them (and Modula 3). Not that C++ does not have its strength , but for many problems Oberon would probably have been the simpler fit.


Impressive!

Yet, when you compile to Lua, the GC and system programming features are moot.


Cute name: ”Luon” means ”I create” in Finnish.


So let's create ;-)


> Luon can be regarded as a statically typed version of Lua. The name is thus a combination of "Lua" and "Oberon".

It's rather curt. How about: Luberon


I can't stop seeing: lube in this name.


What about oilon?




Why not using brackets to replace begin and end ?


Because the language is an Oberon/Pascal descendant.


Right, looks like terrible unreadable mess to me. Somehow even worse than Python, but hey, it could be worse, it could have significant whitespace (though I'm sure the SV Python fetishist """data scientist""" mafia this site is filled with disagrees...)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: