The Senegal Programming Language(github.com) |
The Senegal Programming Language(github.com) |
> Senegal is a powerful, small-but-fast, concurrent, class-based, and dynamically-typed programming language with a modern syntax.
I think the closest thing to it is Wren? https://wren.io/. The difference being that Senegal is compiled and Wren is interpreted.
A few things of interest:
- there are exceptions
- you can call some C code: https://lang-senegal.web.app/docs/cimport
- you can "enhance" (monkey patch?) classes: https://lang-senegal.web.app/docs/enhance
- classic C-style for, while, switch keywords
- there's a pipeline operator, but it's <| https://lang-senegal.web.app/docs/pipeline
- the reference to "switch statements" probably means that switch and if are statements, not expressions
Senegal seems to use a bytecode interpreter: https://github.com/SenegalLang/Senegal/blob/22fe863ad234e43a...
> maybe it's still under construction and the person that posted it just found it too early. But once you're ready to show it to the world, please include the why!
So I don't think we disagree here.
> The owner of this repo owes absolutely nothing to random commenters on HN.
It's not about "owing" anything to anyone, it's about giving useful feedback. If the language has no way to do IO, and nowhere it says that it's a feature, I would have included the lack of IO in my feedback. The author is free to ignore my feedback, just like I'm free to give constructive feedback.
Most comments (so far) are asking "why?". Its honestly a fair question, what does this language offer that others dont? Nothing really, this project isn't anything serious I just wanted to have some fun with it. Regardless, I'll put up a why section.
Reading through the docs I was wondering 'why' as mentioned in another comment. I hoped to find it in the concurrency section and was disappointed to see that it's only single-thread async:
> Coroutines are light-weight thread-like objects allowing you to write asynchronous non-blocking code as well as handle errors in Senegal. The key difference between threads and coroutines is that a program with threads runs several threads concurrently, whereas coroutines run a single coroutine and cooperatively. A coroutine is not paused so that control can be given to another unless and until you tell it to.
There still was a section about C interfacing, but many languages do that. In the end, it seems to be about syntax which is the least interesting thing about a language. What can a new language do that an existing one doesn't do well? If it's a hobby project that's well and good. Only wasn't clear what the intentions/target is from the too brief README.
[0] https://lang-senegal.web.app/docs/enhance [1] https://portswigger.net/daily-swig/prototype-pollution-the-d...
JavaScript uses this because the architecture for accessing fields predates the existence of classes (even then I feel it should be extended to allow fields be accessed without 'this.' if the field and usage exist within the same class definition.)
Surely a compiler should be smart enough to not require a 'this.' if the name is in the scope of the class and not hidden behind something like a parameter with the same name.
Here's an example:
In early versions of Swift, using print("hello world") in a UI class would open a print dialog, because it dispatched the print: instance method on NSView, instead of the global print function.
Python goes one further and requires you explicitly name your this (commonly self) as a parameter. Which is one thing I particularly like about Python, as it’s clear class instance methods are just sugar over plain functions/routines without any magic.
I find the Java-style name resolution that doesn’t require qualification utterly confusing. It would be especially weird/probably a footgun in a JS-like language where functions are frequently used as values and where their names can be shadowed locally.
- If the author already knows some language well, it’s rather inefficient to master another language just to create a new one.
- Rust is likely to be relevant for 11 more years, C is likely to be relevant for 43 more years. Things that have existed for a long time, tend to keep existing longer.
> 1. A hard, enforced separation between stateless functional code and stateful procedural code
> 2. Reactivity as a first-class citizen
Hell yes, I'm in. These two features are interesting enough to try by themselves, I don't even care about the details.
The next most important thing is that JS/TS FFI just works, so I really hope it does.
Your idea of having functions that don't have effects and procs that don't return, reminds me of https://en.m.wikipedia.org/wiki/Command%E2%80%93query_separa... - so there's some prior work there for reassurance and reference.
First class reactivity would be extremely useful - I've thought the same thoughts as you around how reactivity is only partially solved with the current generation of UI libraries (or moreso with RxJS, but the syntax is full of baggage) so I wish you every success with solving it more comprehensively.
{
if (cond) set {a: 1},
for (x of values) set {[x.name]: x},
b: thisob.x,
c: {d: thisob.c},
}
enhanced data transfer, dest.{a, b, [key]} = src
default values, var x = arg ?? 1
optionality and mandatoryness, var x = f?(…)?.info![key] ?? "<not found>"
scope objects and flow control in these, function foo(a=1, b=2) {
scope bar {
let c = 3
scope {
let c = 4
log(a, b, bar.c, c)
baz(scope.this) // a, b, c, bar
baz(scope.arguments) // a, b
break bar
function environments, global.{*} = {a:1, b:2}
var t = proxify({a:3, b:4}, global)
withenv (t) foo() // 3 4
function foo() {
console.log(a, b)
}
and so on. It seems everyone jumps on to “new same language” train when there is so much to do in what’s already not done.The Swift example was caused by shadowing. There was a global print() function and a instance print() method (taking one parameter, sender: AnyObject). If you called print() in a class not descending from NSView it printed the string in the console as expected. But if you called it in a class descending from NSView you got a print dialog as the instance method shadowed the global function. They fixed the issue long ago of course.
However going the other way - calling Bagel from JS/TS - has been on the roadmap from day one and should work pretty seamlessly. Bagel already compiles to TS in fact, including type info.
I have heard of Eiffel though I don't know much about it. I am honestly surprised this concept hasn't been explored more, given how long it appears to have been around.
Wish you all the best with Bagel!
Aside from the traits (typeclasses), most of the inspiration actually comes from OCaml/ML rather than Haskell. The philosohpy is also way closer to the pragmatism of OCaml. I think Rust wouldn't be as popular as it is right now if IO needed a monad, like in Haskell. This would have been too much for a single language. I also don't think that monadic IO is the way. Maybe effects system will bring a more usable way of typing effects (Koka, OCaml soon), but I doubt that they'll come to Rust.