The Bosque language is currently in a very early state with lots of work to do and not ready for practical use. However, I am very excited by the potential in the concepts and wanted to make the project a collaborative endeavor, including both other academics and developer community, from the start. At this point the goal is to explore interesting options in the language design space – whether the Bosque language becomes mainstream or just provides useful ideas for other languages to adopt. So, please take a look, expect plenty of rough edges, and we would love comments, suggestions, and PR’s on the GitHub repo.
A lot of programming languages that are coming out these days talk about simplicity, lowering “cognitive load”, increasing expressiveness, being nimble/lightweight/easy/whatever, and—this one stated by you—reducing “accidental complexity”. When I looked at your grammar and some examples, I saw atomic building blocks that don’t lead to any less complexity than what I’d get if I strung together similar building blocks in Lisp or Python or ML.
To me, “accidental complexity” doesn’t seem like a very well defined concept. I might say such a term in a meeting room arguing to upper management that we need to pay off tech debt. Or I might blog using such a term to talk vaguely philosophically about software engineering. But I don’t think I’d find myself using it in a formal context to argue the merits (or lack thereof) of a technology. I admit that this may be due to my ignorance of a term of art.
The introduction to your publication is even more bold: “Regularized programming” (and hence Bosque) will (supposedly) unleash a revolution on programming the same way structured programming did the paradigms before it, ushering a “golden age” of programming and the like.
Focusing on the term “accidental complexity”, can you elaborate what that means? What is an example of accidental complexity and how does it naturally come about with the current crop of languages. And how—in the large—does this programming language avoid it (or help the programmer avoid it)?
Edit: I see in your publication, upon the mention of “accidental”, you cite “Frederick P. Brooks, Jr. 1987. No Silver Bullet Essence and Accidents of Software Engineering. Computer 20 (1987), 10–19.” But in reading this [0], Brooks says:
> The complexity of software is an essential property, not an accidental one.
He only speaks of certain difficulties as being “accidental”, and past ways in which we’ve improved the impedance of such difficulties.
[0] http://www.cs.nott.ac.uk/~pszcah/G51ISS/Documents/NoSilverBu...
I do not understand the concept op typed strings. Would that not be simple a subtype of strings (implementing additional restrictions on the values of the strings, a true substype)?
Also, when I see something like: 'args.all(fn(x) => x % 2 == 1)' I do experience it as 'simple, obvious, and easy to reason about for both humans and machines' because it only makes sense if you already have a lot of knowledge about languages like TypeScript. I think that something like: 'All x in args: x % 2 == 1' is easier to read. BTW, why does 'fn(x)' not have a type? Are types optional in your langauge?
I would not give examples of mechanisms that have not been implemented and seem to go against your principle ideas, such as references. What happens, I pass a part of a value to a 'ref' argument of a function?
There are some other language out there that are only based on immutable values. If you are fond of immutable values, why not implement them in an existing language and see how far you get. This has the benefit that people do not have to learn a new language and keeps you from reimplementing a lot of stuff that others already have implemented.
I am curious about the following:
> Since the semantics and design of the language ensure fully determinized execution of any code there is actually no real need to perform logging within a block of code. So, logging is not available in the compute language.
While this may be true for execution, this is not true of data on which the program operates. For example, when processing large amounts of data, how should one keep track of statistics, performance information, data irregularities (which don't cause errors but may be useful to look into further), and other such events which might otherwise be logged?
Similarly, suppose the program performs some operation which depends on the system time which fails at runtime for certain system times. If run in deployed mode, it would restart and run the same thing in debug mode, but the environment would be different. How would such an operation be able to be traced back to the particular conditions which caused the error?
From your doc:
>var z = 5;
z = y; //error z is not updatable
"var" is shorthand for 'variable' as you're no doubt aware, so use "const", or use something else altogether to indicate a var.
I stopped reading after coming across your unintuitive "var!" syntax. Let an apple be an apple and an orange an orange.
https://github.com/marcusz/floyd https://www.reddit.com/r/ProgrammingLanguages/comments/arwjl...
1. overall quite nice looking and easy to understand
2. too verbose in places, e.g. this constant structure:
const winPositionOptions: List[List[[Int, Int]]] = List[List[[Int, Int]]]@{
List[[Int, Int]]@{ @[ 0, 0 ], @[ 0, 1 ], @[ 0, 2 ] },
List[[Int, Int]]@{ @[ 0, 1 ], @[ 1, 1 ], @[ 2, 1 ] },
List[[Int, Int]]@{ @[ 0, 2 ], @[ 1, 2 ], @[ 2, 2 ] },
List[[Int, Int]]@{ @[ 0, 0 ], @[ 1, 0 ], @[ 2, 0 ] },
List[[Int, Int]]@{ @[ 1, 0 ], @[ 1, 1 ], @[ 1, 2 ] },
List[[Int, Int]]@{ @[ 2, 0 ], @[ 2, 1 ], @[ 2, 2 ] },
List[[Int, Int]]@{ @[ 0, 0 ], @[ 1, 1 ], @[ 2, 2 ] },
List[[Int, Int]]@{ @[ 0, 2 ], @[ 1, 1 ], @[ 2, 0 ] }
};
Has types defined in 10 places, 9 of which are redundant.Also you are using @{...} for lists and @[...] for tuples; a more usual convention (in e.g. Python or Haskell) would be [...] and (...) respectively.
3. String types aren't intuitive (at least to me). E.g. in this code:
const playerX: String[PlayerMark] = 'x'#PlayerMark;
It appears that a String[PlayerMark] is a subset of String that can have the values 'x' or 'o'.I would have preferred something like:
type PlayerMark = 'x' | 'o';
type PlayerMarkOrBlank = 'x' | 'o' | ' '; point<~(y=value)
instead of other languages' point.y = value
?I believe that syntax should be designed to make things simple for developers, not for the designers of languages or for compilers.
"point.y = value" is typically a statement for a single update of a mutable record.
I'm not sure how you'd extend the latter to support the features of the former. The meaning is completely different. Different things should look different.
point.copy(y=value)--Niklaus Wirth (Good Ideas,Through the Looking Glass)
Obviously someone please correct me if I'm wrong.
As I mentioned in the discussion two days ago, PL researchers throw around these terms but never actually measure them. You can learn a lot from a small user study.
I think this is the one that should be highlighted most. Otherwise, from an engineering perspective, many of the other language features have already been implemented and widely used in other languages
https://writing.kemitchell.com/2019/03/09/Deprecation-Notice...
Either Apache 2.0 or Blue Oak Model would be better choices.
I suppose if the learnings of Bosque find their way into TypeScript that might be useful but I don't see a practical use for Bosque as it is. Either that or I've completely missed the point.
var v: List[Int ?] = List@{1, 2, none, 4};
OK! I think it needs some work. AM I supposed to intuitively know what ? and @ mean?
O.o
Why? What even was the point in making them 'typed' then?
Also, what exactly are the relevant language-level details which BOSQUE contributes? It seems more like a large library than anything else.
That said, some of the refinements, especially the (TypeScript-inspired?) record typing and manipulation facilities, look quite pleasant.
> Bosque is designed to encourage limited uses of recursion [and using map/filter etc instead]. This is done by introducing the rec keyword which is used at both declaration sites to indicate a function/method is recursive and again at the call site so as to affirm that the caller is aware of the recursive nature of the call
i don't think i've seen a way marking functions that might not terminate at the call site. (though termination doesn't seem to be a specific focus here)
I'm still not sure what is the raison d'etre here.
Why would I use this instead of, say, Rust to WASM?
Along with literally every other language. I really wish the splash pages for new languages would cut the boilerplate and just open with a list of the specific traits that make this one different from its peers.
Edit: it appears that this is relatively easy to find after visiting the repository. Still, that opening paragraph is meaningless, and many languages don't even make the worthwhile bits easy to find for those who actively seek them.
The fact that there are idioms that they could use doesn't mean those idioms are natural to the way people think, in particular, to the way they think when trying to solve problems.
I avoided a fully functional style in my language[1] (even it has a functional kernel) because I've watched people write code while working with them or as interview candidates, and observed them (and myself, tbh) having trouble solving problems with "big" elements.
Thinking about the whole array makes it "big" mentally. I'm not a psychologist or a linguist, so I can't tell you what that means, just that I've observed a pattern. When I was doing interviews, we had the infamous stars question, which goes like this: "Imagine you're trying to find the (maximum distance) of all the stars in the sky. How do you compute this?"
Candidates reliably get hung up on "all the stars in the sky" and don't realize they can break the problem into the current maximum star plus all the rest of them. (That some people get it and some just don't is why I don't use the question.)
With the humble for loop, you're naturally dealing with a single thing at a time. That's why I think it's unwise to throw it out and only use functional constructs.
And that said, often we do want to address the whole structure. When you look at problem solving, it's about reexpressing a question in such a way that the answer falls from it naturally. To do that, we need a multitude of idioms that can expose different aspects of a problem and be composed reliably.
> We believe that further work, such as identifying recursive idioms or other fundamental algorithmic patterns, can further reduce the need for unstructured recursion – eventually limiting it to an infrequently used part of the language.
I do agree with this. If you're going to have find, map, filter, etc. then it makes sense to have a generalized tree-walking algorithm. That's how I'd probably like to express it.
But, again, when I'm solving the problem initially, I need to be able to deal with small things to keep it all in my brain at once. That's how we teach it and often how we will want to express it to ourselves when we're in the fog of solving an unknown.
I absolutely would love something that could describe boundaries, enforce invariants and make guarantees that a traversal won't hang, but I wouldn't want that to be the only way to express such traversals. Development is an evolutionary process; we often start with something that might suck but is viable, and then iterate and improve it.
Edit: Funnily the issue ( I & l )is now visibly noticeable with HN's font choice
Might be a bit over-critical, but when I read that it's main selling point is making it more human readable, this seems a bit troll