5 ms·
Show HN: qdbp – a minimal, elegant, safe, and expressive programming language
I started working on qdbp about a year ago after coming to the conclusion that modern languages were way too big, complex, and unwieldy. qdbp is the philosophical opposite of languages like C++ - it is tiny, and will stay that way. The language itself comes with no if, loops, switch, macros, etc. However, the few constructs that qdbp does have, along with its unified syntax, can compose to form higher level abstractions(like if, loops, switch, defer, monads, domain specific languages, etc). A few key points:
- qdbp is statically typed and types are fully inferred, meaning there are no type definitions or annotations
- The language uses prototype based OOP centered around anonymous records and polymorphic variants. It has a syntax heavily inspired by Smalltalk and Self
- Unlike virtually any other OOP language, qdbp has no mutation or inheritance(it instead has record extension, which is very similar to single inheritance)
I'd really appreciate it if you checked out my language!
https://www.qdbplang.org/ https://www.qdbplang.org/
https://github.com/dghosef/qdbp https://github.com/dghosef/qdbp
- GianIsAlive 3y agoInteresting. I like the aesthetic. Personally I'm not good at reading shorthand and lambda functions in python. I rather type it out fully to help with clarity. But the simplicity is intriguing. I can totally see people find joy program in it :)
- dghosef 3y agoThanks! That was what I was going for.
- speps 3y agoVery elegant, good job! Although I'm surprised there's no mention of REBOL or Red[1]. Very similar philosophy regarding constructs and keywords. [1] https://www.red-lang.org/p/about.html https://www.red-lang.org/p/about.html
- dghosef 3y ago> Very elegant, good job! Thanks! > Although I'm surprised there's no mention of REBOL or Red[1]. Very similar philosophy regarding constructs and keywords. I am not too familiar with either language. It seems like we have very similar philosophical goals but with very different approaches. Red/REBOL are minimalistic but extensible with macros/homoiconicity, while qdbp is minimalistic but has a versatile object system and expressive syntax allowing many constructs to be built as libraries. I debated adding macros, but decided that qdbp was expressive enough as is and macros would probably double the complexity of the language.
- JonChesterfield 3y agoMinimal and no mutation is my preference too. How do you express recursion? E.g. the standard factorial example. In particular, the self reference implies a cycle but the website claims an acyclic heap managed by reference counting. If there is no "purely functional IO", what IO is there, and what prevents programs from using it to build a mutable local variable? The Boolean example that states it includes all the primitives doesn't do IO which suggests the language may have no IO available. There's a print example which suggests it has stdout and the documentation is wrong. "Phantom fields" look very like the name in nominative typing. Interesting that structs can be given more than one empty field as an equivalent to multiple names.
- dghosef 3y agoThanks for the questions! > How do you express recursion? E.g. the standard factorial example. factorial := { val | val = 0. True? [1] False? [val * (self! (val - 1)).]. } factorial! 5. Print. The self reference does not imply a cycle. The reasoning for this is a little subtle. object := { Foo[3] Bar[self Foo] } object Bar. under the hood desugars to something like the following object := { method Foo(self) {return 3} method Bar(self) {return self.Foo()} } object.Bar(object) self is nothing more than a sort of syntax sugar for a parameter whose value happens to be the same as the enclosing prototype. In general, it is impossible for an object to refer to itself because an object doesn't have access to itself until after it is created. Yes, methods within an object have a self parameter, but the method itself doesn't have a reference to the enclosing object captured - it is passed in every time the method is called. I'm not sure that was the best explanation, and I would be happy to field any clarifying questions. As a side note, the documentation is a little bit unclear. Yes, qdbp has no cycles and can potentially be reference counted, but at the moment it is garbage collected and reference counting is TBD(probably in the next month or so). > If there is no "purely functional IO", what IO is there, and what prevents programs from using it to build a mutable local variable? There is no purely functional IO, there is just "regular" IO. There is nothing in theory that, for example, stops a program from building mutable state in an external file or something like that. I am just assuming that programmers will do things like that sparingly, which I think is a fair assumption to make. Printing is not a primitive. It is a method within a string object. I guess, though, the boolean example is missing the FFI primitive that the Print method uses under the hood. > "Phantom fields" look very like the name in nominative typing. Interesting that structs can be given more than one empty field as an equivalent to multiple names. Yea upon discovering the idea I thought it was pretty cool and is a way to recover many of the drawbacks of structural typing.
- deleted 3y ago[deleted]
- xigoi 3y agoSo a Smalltalk-like language, but with static types? Nice, I was looking for that!
- dghosef 3y agoqdbp is sort of what would happen if self(which is similar to smalltalk) and ocaml had a kid together :)