The Oberon+ Programming Language
oberon-lang.github.io
oberon-lang.github.io
If only the FPC compiler supported it and allowed combining units in Oberon with Pascal ones in one project!
The language specs: https://github.com/oberon-lang/specification/blob/master/The...
Relying on expressions greatly reduces the need for transitory variables, and in case of Pascal, where you can't just declare them as you go, this would be especially important to clear the code from ops inessential to the task at hand.
`let foo = if (bar > 0) then bar else frobnicate() end` would be nice to have, as well as begin-end blocks with their own scope (can't fathom the reasons it's not allowed) and evaluated to the last statement. Rust and Nim get it mostly right.
I'm not against evolution, especially when you have others to test the feature extensively for years. But I'm not a language designer and my opinion on the matter holds no weight.
declare
function f (i: Integer) returns Integer is ( i * 2 );
x : Integer;
begin
x := f(21);
end;It's a bit interesting that I initially stumbled on Oberon+ while searching for something typed which compiles to straight Lua and was surprised seeing the scope of the project.
In any case, I wish you all the best in the development of the language!
> when the user base is still slim you have much more freedom to be a bit more adventurous, add and deprecate things more freely
When designing a language, it's hard to get rid of the initial sins, so if in doubt, leave a feature out, so you don't regret it later; once enough people are involved with the language and writing code with it, any change that isn't backwards compatible is an imposition on everyone involved.
Playing the devil's advocate: On the other hand, making a whole new language is rarely a way to GTD now, it's usually an investment in the future. For surviving into that future the language usually needs the involvement of the community. And for that one has to consider what new/different/radical things does the language offer to the public to hook them on. May be it's OK to sin a little and get straight closer to v1.0? Of course, a few will hurt but they'll live.
Maybe what we really want would be semantically close to Oberon+ but abandoning Wirth's surface syntax. (You could still respect the design discipline of allowing a simple fast compiler.)
making a mish-mash of variable declarations and code would make it quite easy to inadvertently add a new variable similar, but not identical to an existing one, for example.
It's good that procedures and functions in pascal are different. One of the big problems with C is that you can leave function results dangling, which works against the clean separation of purposes... procedures have side effects, functions tend not to (but can).
One of the most clever things in pascal is assignments := are very hard to confuse with tests for equality =. You're not likely to accidentally confuse them.
Show HN: New Oberon+ to C99 transpiler for near native performance - https://news.ycombinator.com/item?id=29591993 - Dec 2021 (2 comments)
The Oberon+ Programming Language - https://news.ycombinator.com/item?id=27864582 - July 2021 (4 comments)
The new Oberon+ programming language – modern simplicity - https://news.ycombinator.com/item?id=27855767 - July 2021 (4 comments)
Others? (Lots of original Oberon, of course)
https://oberon-lang.github.io/2021/07/15/motivation-for-a-ne...
How about a treesitter-based editor extension that converts between begin/end and {/}, as if they were ligatures? Actually this might not even need treesitter.
See emacs prettify-symbols-mode (https://emacs.stackexchange.com/questions/46529/configuring-...)
Neovim has the conceal feature, which can convert Treesitter nodes into a single symbol, but not the other way around unfortunately.
Rochus is almost kind of doing this with Oberon+ versus Wirthian Oberon already, but it would be nice to go further.
https://www.microfocus.com/en-us/products/visual-cobol/overv...
For example, to call a function, we just use the name of the function and parentheses, rather than saying "call". This is useful, because it allows the reader to focus on what is of interest.
speaking as an ex professional delphi programmer here - i have written lots of object pascal code, and have no desire to write any more.
but to be pedantic, i think you mean define rather than declare, though of course you can also declare things at different scopes.
int x;
f();
x=3;
The improvement was allowing declarations anywhere.(I assume f() is a call.)
If you try to use `x` before it is defined (the assignment) your compiler should give you a warning, at least. If it doesn't, find a new compiler.
> A definition of an identifier is a declaration for that identifier that:
> — for an object, causes storage to be reserved for that object; [...]
But initialization (in C) does not occur for block-scope objects without the optional initializer.
(Granted I am touch typing and also using Colemak layout, so rarely ever move my hands. For people that hunt and pek, I believe curly braces are easier to type.)
I don't think there is much practical difference between curly-braced vs keyboard based syntax. Both are similarly easy to read, especially with syntax highlighting. After a while, your brain will automatically parse "begin" and "end" as a symbol, same as curly braces, so you won't notice the "noise".
As for the pros and cons:
Pascal style syntax is slightly better for new people learning to program. Learning how to even type those weird curly braces and understanding the difference between all the styles of braces just takes focus away from actually learning how to program.
Curly braced C-style syntax is better for people that already know how to program because everyone is already familiar with at least one curly braced language.
so, logically, they must have learned how to use {} in the first place, probably with few problems.
i have taught god-knows how many people c and c++ (used to be a commercial trainer for those languages) and i can assure you that very, very few, if any, had problems with {}.
For 35+ years I’ve been using right-shift for things on the right side of the board, cranking my hand and stretching my fingers and complaining about programming languages with poor typing ergonomics.
It’s taking forever to break the habit, but so far it feels so much better.
I've not been very successful changing this habit.
I think playing video games has made LeftShift + letter a really easy combo, right shift feels quite uncomfortable, but I did find that I use it when typing !
I didn't know it at the time, but that one semester class was immensely useful for me throughout my career.
The teacher was a bored and unpleasant secretary and the typewriters were mechanical (and the shift keys so heavy for our pinkies) but it was still the most useful thing I did in school since I learned to read in first grade.
Type, maybe, but they are visual noise when you read code.
BEGIN and END are also not as easy to match with editors/IDE's as pairs of symbols.
Of course some people can't read words by shape and instead have to sound out the individual letters every time, so I guess it can be more annoying for some people.
And I don't mean to be patronizing, I actually have the opposite problem. I am faster at parsing whole words than symbols which is why I really struggle with modern UI that solely relies on icons. It drives me mad.
proc Something()
begin
...
end Something
not the interface/impl declarations. Which actually makes this worse.It's a single-user workstation, developed from the CPU on up, compiler & language, OS with unique GUI, all documented in a book, and you can run it online in a browser via a JS emulator for the CPU: http://schierlm.github.io/OberonEmulator/
People used it at ETH as their main system to run the University!
Fascinating stuff!
An identifier declared in a module block may be followed by an export mark (* or -) in its declaration to indicate that it is exportedhttps://oberon-lang.github.io/2021/07/17/considering-generic...
Specifically in Oberon-07 when you have a module "Foo" with a type "Bar" you use it in another module as "Foo.Bar". With parametric modules, a "Foo<T>" module would need to be imported an a specialized form as -e.g.- "Foo<INTEGER>" and thus the "Bar" type would need to be used as "Foo<INTEGER>.Bar".
In my mind that was both the simplest and smallest change that would allow for the most flexibility (the parameters would be any token acceptable by the language, not just types, meaning that they could be used for constants or even affect other imports).
I did consider implementing a compiler for this, but then i decided that if i'm going to make a compiler for an incompatible language that already practically nobody uses, might as well make my own language that also changes some things i dislike about Oberon-07 (like the uppercase keywords, using # for the inequality string and * to export stuff from modules).
As for it being implemented, I was assuming that by now it already was, given that it is still being actively developed.
I didn't find a compiler yet which implements the proposed templates; if you know one please post a link.
Here is how it looks like in Modula-2.
https://www.modula2.org/reference/isomodules/isomodule.php?m...
Free Pascal has threads.
[1] https://www.pcorner.com/list/PASCAL/TASKER4.ZIP/TASKER.PAS/
I asked the oracle
> Wirthian functional programming language would emphasize simplicity, elegance, and readability while incorporating functional programming concepts such as immutability, first-class functions, and recursion. It would provide strong typing, modularity, and a minimal standard library, staying true to Wirth's design principles.
It also tells me that Elm, Idris, PureScript, F* and Gleam share many of these same qualities.
The thing that I didn't appreciate about the design of Wirthian languages earlier is that he really focused on mechanical and compiler-writer sympathy, designing languages that were fast and easy to compile.
I just discovered Pascal-S, it is like Cool or ChocoPy, a subset language designed for compiler students to implement.
https://static.aminer.org/pdf/PDF/000/530/289/pascal_s_a_sub...
- Don't throw everything into a single global heap
- Don't rely on stop the world GC
- Support actors and zero-copy message passing
.. in other words, be like Pony's ORCA.
From here: https://oberon-lang.github.io/2021/07/15/motivation-for-a-ne...
And yet it carries over all of the inanities of the many Oberons before it like:
- Four different loops (while, for, repeat, and loop)
- Useless distinction between procedures and functions
- Randomly selected ASCII symbols to show what is exported and/or read-only
- extremely awkward and limited exception handling (you have to call a procedure that cannot hav a return type using a built-in pcall procedure that writes exception info into a variable you pass into it)
and so on.
All of Oberons are just walking around in circles re-implementing the same weird ideas again, and agian, and agian, and again.
I agree with the rest, but the rest of the language is great.
When they have similar semantics, and are not arbitrarily designed.
In Oberon:
- while has an elseif statement. Repeat is a do/while, doesn't have an elseif statement
- loop is allowed an exit. No other loops are allowed to terminate early. And that is literally the only reason loop exists
etc.
Early Pascal/Modula/Oberons were extremely anal about loops (of any kind) never having any early exits, ever.
Then they ran into the real world.
So each consecutive version of Oberon either added early returns or removed early returns. Sometimes like clockwork. And also added/removed other types of loops in pursuit of some unspecified ideal of simplicity.
You can see part of that history in the overview of differences: https://oberon-lang.github.io/2021/07/16/comparing-oberon+-w...
So it's a self-imposed constraint that makes very little sense.
The design is well-balanced and simple, and you can do essentially everything you can do with Java exceptions, just without complicated syntax constructions; see https://oberon-lang.github.io/2022/05/15/towards-exception-h... for more details.
You cannot handle handle exceptions in a block of code without extracting into a procedure... that cannot return anything.
Yeah, I doubt you can "do everything you can do with Java expressions.
And of course Oberon's syntax construction is more complex: you need to have an external variable that gets populated, you need to match on three different types etc.
That's a one second problem; just give back the value via VAR parameter; the design decision is well justified in the referenced article.
> do everything you can do with Java expressions
"exceptions", not "expressions"; what do you think one cannot do with the Oberon approach?
> you need to have an external variable that gets populated
That's the Pascal philosophy; even an index variable of a FOR loop has to be declared up front in the declaration section; either you like it or not; personally I prefer the in-place declaration approach, but the language would become much more complex and it doesn't make sense to just rebuild C++ or Java.
Ah yes. "Just".
And these people accuse other languages of having complex syntaxes or complexities in general.
> what do you think one cannot do with the Oberon approach
I think it's obvious what I wrote. You can't wrap blocks of code, to do that you need to extract it into a proc that among other things (like actual params passed to it needs an additional parameter) needs an awkward `out` parameter etc.
Is the result sorta kinda equivalent to Javas? If you squint hard enough, yes
> That's the Pascal philosophy; even an index variable of a FOR loop has to be declared up front in the declaration section
I know the Pascal philosophy: create awkward verbose languages with useless constraints while claiming it's for the sake of simplicity.
> but the language would become much more complex and it doesn't make sense to just rebuild C++ or Java.
1. There's nothing wrong with complexity
2. There a multiple languages that don't have Pascal/Oberon's constraints, decisions, and awkward workarounds which are neither Java nor C++
But you don't like the distinction between procedures and functions or different types of loops? Pick a side here.
I think that having four different loops is better than jumping through four different hoops for different loop styles.
In Oberons you jump through the hoops because only `loop` is allowed to have `exit`, for example. Which is a constraint for the sake of constraints. Repeat is a do/while, but it doesn't have while's elseif statement. Again, because reasons. And so on.
Oberon is nothing but hoops instead of loops.
[1] Go's decision to not include do/while is on par with Oberon's decisions for loops: stupid and unreasaonable.
Uh? care to elaborate?
A function is a function that returns something.
Oberon+ keeps it's predecessors' idiotic distinction, but takes it one step further: both functions and procedures are decalred with `proc` or `procedure`, functions are `proc`s that have a return type.
And yet:
- procedure calls don't have to specify parameters apparently, but function calls must specify all parameters
- functions cannot be used in Oberon+'s weird exception handling. [1] You do a call with `PCALL(res, P, args)` where res is a variable that will hold the result of the exception if it happened, and P is the procedure. You cannot pass functions (aka procedures which have a return type)
As the spec so wonderfully says [2],
--- start quote ---
There are two kinds of procedures: proper procedures and function procedures. The latter are activated by a function designator as a constituent of an expression and yield a result that is an operand of the expression. Proper procedures are activated by a procedure call. A procedure is a function procedure if its formal parameters specify a result type. Each control path of a function procedure must return a value.
--- end quote ---
[1] https://github.com/oberon-lang/specification/blob/master/The...
[2] https://github.com/oberon-lang/specification/blob/master/The...
what's oberon+ for?
its interesting that there is supposedly an os in oberon that actual uses the same language for the shell or something or the kernel is written in it or something like that but this page just makes me think its not worth looking into after all
How does Unicode support make it harder to audit code?
This is a common misconception. Oberon's text-based user interface lets you invoke commands in the M.P form, but it doesn't really have a shell language—at least not in the familiar sense—and to the extent that something like one kind of exists, it certainly isn't the same as Oberon-the-language.