4 ms·
I am always happy to see people make their own languages and write about it. For this article in particular, I disagreed with the first two parts: 1. Premise:
by sshine 4y ago
I am always happy to see people make their own languages and write about it.
For this article in particular, I disagreed with the first two parts:
1. Premise: Simplifying assumption: There are two kinds of languages, static and dynamic. Somehow, it's just good to know this, and nothing is said of which of these the Duck language fall into.
2. Syntax: Wait, no.
There is an implicit premise here, being that if you make a language, it's probably going to be a general-purpose one with expectable control-flow structures, and because of that, what we care about is how those control-flow structures look, i.e. should there be curly braces around blocks and such.
A premise I would prefer is: When you make a language, you want to solve a problem. Imagine a language being an overgrown library. You don't start a tutorial in making libraries about how a good library interface looks like. You start by saying what problem you want to solve.
Another premise I would prefer is: Most problems are domain-specific, so most language-shaped solutions to problems are DSLs.
- Joker_vD 4y agoAnd speaking of control structures... index, value := with i := 0 count := len(haystack) loop while i < count else not_found elem := haystack[i] if is_special(elem) then continue if match(elem, needle) then break found(elem) // could also have been // while not match(elem, needle) else found(elem) // until match(elem, needle) then found(elem) always i = i + 1 on not_found -1, _ on found(result) i, result // "i" is in scope here, but not "elem" ... That, I believe, is one of the most generic forms of a loop, with a pre-header for declaring loop-local variables, multiple exit points (that accept parameters!), flexible condition checking ("while/until" being syntax sugar for "if ... then break ...", "continue" is "goto" the "always" block), and expanded space for the increment statement — and AFAIK no modern language supports it. I mean, if you are making a new language, that's your chance to not stick with the old and tried stuff but try something more adventurous, like this loop device from Knuth's old paper.
- Jim_Heckler 4y agofrom what i can tell, the only things here not supported by CL's LOOP is "continue", and there being named exit points with parameters, though I fail to see the usefulness of that when you could just use return.
- touisteur 4y agoYes especially if you can make an inner (embedded) function just for that, that won't spill over the global function namespace. Ada's good in that aspect.
- duped 4y agoI think the reason you won't find this in many languages is because people gravitate towards fewer constructs rather than more, and this syntax can be expressed using more general purpose semantics without any additional cost. The syntax debate is usually something like, "what does this buy us and do we have the budget for it" and imo that loop syntax is not sufficiently general (it cannot express recursion, for example) nor does it make code easier to read (you now have what's essentially a few if/else blocks split across four different code blocks, I would reject this if I saw it in a code review to make the loop simpler), and it doesn't really prevent a user from making mistakes. Extremely generic control flow constructs have also been shunned a bit. There's a lot of "call/cc considered harmful" content on the internet from a few years back, and I predict we'll see the same thing about new-fangled control flow constructs like algebraic effects.
- Joker_vD 4y agoThere are languages with while cond1 stmts1 elif cond2 stmts2 elif cond3 stmts3 syntax which is essentially a few if/else blocks pulled up to the enclosing loop level. Makes writing e.g. while a > b a := a - b elif b > a b := b - a somewhat more concise. And Rust's "while let" loop easily could have allowed several clauses instead of single one. And yes, you can express all of that with either "while true: ..." with early breaks/returns or with "while <OR'ing lots of Boolean flags>: ..." with post-processing those flags to determines why the loop has ended... but why not have explicitly named, limited continuations? IMO it would simplify dealing with "there maybe many reasons why the loop ended" kinds of iterations. Putting every loop into its own (anonymous) function that returns an ad-hoc sum type doesn't sound like a much better solution to me, to be fair.
- danielvaughn 4y agoThank you! This is something I've encountered in every tutorial on language design. I've been trying to build a DSL for years, but I'm stuck because everything I read isn't suitable for my use case. Part of me wants to just say "fuck it, I'll learn how to build a GPL, then hopefully by the end of it I'll have enough on-hand knowledge to transfer over". But I really would rather not spend that much effort.
- hardwaregeek 4y agoI think there are definitely wrong answers to syntax if you want people other than PL nerds to use your language. Agreed that a library shouldn't start its tutorial talking about how nice its interface is. But at a certain point, you should probably come around to a syntax that is fairly standard. There's a reason a lot of UI libraries standardized around JSX. Basically, syntax might be your last thought, but that doesn't mean you should neglect it.
- sshine 4y agoSyntax is the bike-shedding of programming language design. Imagine you're going to write a book, and before you think of the subject, you're rabbit-holing whether or not to use the Oxford comma. This is literally the significance of syntax. Of course, it matters. But not as much as what your book is about.
- ogogmad 4y agoWhat DSLs might someone make today? And when should they be libraries instead? [edit] There was a recent example of a constant-time C-like programming language: https://news.ycombinator.com/item?id=33308037 https://news.ycombinator.com/item?id=33308037
- spacechild1 4y agoOne good example that comes to my mind is audio programming / live coding languages.
- sshine 4y ago> What DSLs might someone make today? Oh, but there are SO many! These two super-categories I am very fond of: - Query languages - Infrastructure specification languages Here are some concrete examples: GraphQL: An API query language: https://graphql.org/ https://graphql.org/ jq: A JSON command-line processor: https://stedolan.github.io/jq/ https://stedolan.github.io/jq/ HCL: A DSL for expressing Terraform assets: https://developer.hashicorp.com/terraform/cdktf/concepts/hcl-interoperability https://developer.hashicorp.com/terraform/cdktf/concepts/hcl... Troll: A DSL for expressing dice roll simulations: http://hjemmesider.diku.dk/~torbenm/Troll/ http://hjemmesider.diku.dk/~torbenm/Troll/ fvg: Functional Vector Graphics: https://github.com/lemmih/fvg https://github.com/lemmih/fvg Kleenex: Optimal regex-based stream processor: https://kleenexlang.org/ https://kleenexlang.org/ Futhark: High-performance purely functional data-parallel array programming: https://futhark-lang.org/ https://futhark-lang.org/ > And when should they be libraries instead? A friend recently told me that DSLs (stand-alone) and eDSLs (embedded in an existing language) have the main difference that DSLs are overgrown configuration files, and eDSLs are overgrown libraries. I'd say: When you want to call your DSL from more than one programming environment, it is good to have an abstract representation that transcends one particular syntax-tree definition. A library is good until then.