Hacker Newsnew | past | comments | ask | show | jobs | submit | throwaway17_17's commentslogin

Not to derail this thread on Mach, which as I stated in another comment has some pretty appealing characteristics for me, but since you’re here and the dev of another ‘low-level’ programming language:

I read through a segment of your language’s docs when it was on the front page a couple of days ago ago. Since you’re talking safety’s is there a link (or just a suggested starting point) to read about Ü’s safety mechanisms and guarantees?

I feel like I sit along a different axis in the safe versus unsafe discourse, so I don’t discount languages like Zig or Mach for not providing opt-out safety for certain areas of concern and I don’t give extra credit to languages like Rust or Ü for having those features. What I am interested in is what choices where made and why, then what do those choices mean for me as a potential user of a language.


Rust have shown that safety can be achieved without sacrificing performance and many other aspects of language design. My language Ü proved this to be true too. So, I now see no reason not to incorporate safety mechanisms into newly-designed programming languages. For me adding no safety mechanisms is like not including safety belts and airbags in a newly-built car. That's why ask the same question again and again under each Show HN post presenting a new language.

> I feel like I sit along a different axis in the safe versus unsafe discourse

I can't believe someone can be neutral in this question. If you do actually write code in unsafe-languages, you are eventually forced to find a fix memory-related bugs and other bugs caused by their unsafety. Maybe you just don't need writing such low-level code and use some high-level language without direct memory access instead?

> what choices where made and why

In many cases there is no answer. My experience shows that many design decisions are made without thinking too long. One often just needs something to work right now rather than spending much time carefully designing each language feature. It's especially true for pretty-young language projects like Mach.


I find the goals of explicitness and maintainability to be really pitched to my current taste. From a quick view it looks like the syntax is approaching a local maximum for conforming to expectations and not sacrificing the explicitness sought.

As the developer, where do you land on meta-programming for the language? I applaud the straight up nature of ‘the battery will never be included’ and the reminder to consider the possibility of a feature being a library instead of a syntax or language feature. I certainly don’t think meta-programming is essential, but the ability can contribute to the ease of use for library code.

And I’ll ask now since it always comes up, where does Mach stand on ‘advanced’ type theory uses for ‘low-level’ programming? I noticed the admonition that safety is the developers job which is sure to bring some ‘heat’ from the memory-safety-is-table-stakes crowd, in light of that, where does Mach stand regarding ways to ensure ‘safety’?


I played around with an entire branch of the language that used a zig-style meta programming type system and it ended up just getting in the way more than it helped.

The only thing I may consider in the future is something along the lines of a VERY weak macros system, but that's a highly well explored and well known footCANNON that I'm not keen on implementing. I do have designs in mind if it ever becomes an essential, but for the foreseeable future, any sort of metaprogramming is practically off the table.

On safety... That's a big one. I'm absolutely prepared to take smoke for that all day and I know I will be. Memory management is one of those problems that every programmer has to deal with at some point in their career, whether it's fighting a GC, fighting a borrow checker, or fighting poorly written code. I decided to go "back to basics" and encourage programmers to fight their own knowledge of the system and to be more aware of the code they are writing. Yes, that means that it can be more difficult to write code that is... "safe"... but when it comes down to it, Rust and C are both compiled to CPU instructions that have no concept of memory management intrinsically. Taking the load off the developer has the side effect of removing total control with it. In my opinion, it's a situation of throwing the baby out with the bath water for a benefit that can be fully achieved through best practices and proper understanding of the code you're writing. Does that help clarify my stance? I hope it does lol

Glad you took the time to explore the project! Thank you for that!


In the ‘Caveats’ section the author discusses that the advice only applies to types constructed via Record Syntax and that datatypes with positional arguments are exempt from the rule/preference proposed.

I wonder if the argument for the do notation’s usage being better along several metrics can stand generalization. There are sometimes discussions about the merits of named argument to functions and data constructors versus the much more common positional syntax, the arguments made in favor of more ‘broad spectrum’ named arguments reflect the more specific pro’s being argued in TFA.

It would be interesting to see what types of syntax additions, and the accompanying weight of those additions throughout an entire code base, would prove an acceptable trade off for moving away from positional arguments being the default. I almost assume the extra line noise and extra name selection would be the most negative effects, but the most positive effects are harder for me to guess at. But overall, the reaction of devs to more ‘book keeping’ in there code is hardly ever positive.


Smalltalk keyword message syntax seems to be in a middle ground


After so wrote the comment below I realized that it really is just ‘um, actually…’ about discussing using concurrency vs implementing it. It’s probably not needed, but I do like my wording so I’m posting it for personal posterity.

In the context of an article about C++’s coroutines for building concurrency I think structured concurrency is out of scope. Structured concurrency is an effective and, reasonably, efficient idiom for handling a substantial percentage of concurrent workloads (which in light of your parent’s comment is probably why you brought up structured concurrency as a solution); however, C++ coroutines are pitched several levels of abstraction below where structured concurrency is implemented.

Additionally, there is the implementation requirements to have Trio style structured concurrency function. I’m almost certain a garbage collector is not required so that probably isn’t an issue, but, the implementation of the nurseries and the associated memory management required are independent implementations that C++ will almost certainly never impose as a base requirement to have concurrency. There are also some pretty effective cancelation strategies presumed in Trio which would also have to be positioned as requirements.

Not really a critique on the idiom, but I think it’s worth mentioning that a higher level solution is not always applicable given a lower level language feature’s expected usage. Particularly where implementing concurrency, as in the C++ coroutines, versus using concurrency, as in Trio.


Is there a reason Rust would not (as it was done in the ‘good ole days’) index the table via pointer arithmetic from .data? Also, I’m assuming that because you are discussing new devs, that they are not making the implementation decision to place the table on the heap and using Rist’s subscript operator, which I would understand Rust not doing as default. I can not think of a reason that the table should ever be put on the stack for reading a single value, so that being the default seems an oddly pessimistic default. I could be missing something regarding how Rust handles literal data ‘written out’ into source though.


The table is on the stack because we conjured into existence a temporary, so it's exactly as if the programmer had conjured the variable as a local by hand. Suppose our table is named SOUP

    const SOUP: [f32; 1000] = [ /* whatever */ ];
    let foo = something(blah_blah, blah) * SOUP[4];
    // The optimiser will see that SOUP[4] is exactly say 1.5_f32 so it'll just do
    // the same as if we'd calculated something(blah_blah, blah) * 1.5_f32
However

    let foo = something(blah_blah, blah) * SOUP[blah];
Now blah is a variable, we might need any value from SOUP, the optimiser doesn't know what values it might have - so a temporary is conjured into existence, equivalent to:

    let tmp = SOUP;
    let foo = something(blah_blah, blah) * tmp[blah];
You do presumably recognise that this now puts SOUP on the stack right? The temporary is equivalent, but without the explicitness.

Now if you know what you're doing you would of course have one single place in your program where you do this:

    static SOUP: [f32; 1000] = [ /* whatever */ ];
And now there's an immutable global named SOUP and like "the good ole days" we don't keep writing this huge data blob to the stack only to subsequently look at a single element. But that's not the thing the noob wrote so that's not what they get.

"Sufficiently smart compilers" are a very gradual miracle. In theory a compiler could realise this is a good idea, in practice today I doubt you will find such a compiler, so just write explicitly that you want a single variable if that's what you want.


Regarding your mention of compiler magic and Swift, I don’t know much about the language, but I have read a handful of discussions/blogs about the compiler and the techniques used for its implementation. One of the purported benefits/points of pride for Swift that stood out to me and I still remember was something to the effect of Swift being fundamentally against features/abstractions/‘things’ being built in. In particular they claimed the example of Swift not having any literal types (ints, sized ints, bools, etc) “built in” to the compiler but were defined in the language.

I don’t doubt your point (I know enough about Swift’s generic resolution crapshow during semantic analysis to be justified in assuming the worst) but can you think of any areas worth looking into for expansion of the compiler magic issues.

I have a near reflexive revulsion for the kinds of non-composability and destruction of principled, theoretically sound language design that tends to come from compiler magic and shortcuts, so always looking for more reading to enrage myself.


> literal types (ints, sized ints, bools, etc) “built in” to the compiler but were defined in the language.

This is actually a good example by itself.

Int is defined in swift with Builtin.int64 IIRC. That is not part of the swift language.


I don’t know if the language is yours, but I think the wording and its intended meaning (the sentence starting with ‘The core implementation…’) may be one of the most concise statements of my personal programming language design ethos. I’m jealous that I didn’t come up with it. I will certainly credit you when I steal it for my WIP language.

I will be adding the following to my “Primary Design Criteria” list: The core design and implementation of any language feature is explicitly targeted at the efficient creation of opinionated, composable abstractions rather than providing those abstractions at the language level.


I think your comment leads to discussing a distinct third ‘cause’ for open source development: where a developer realizes their ambition is greater than their abilities, either in the technical sense or (more likely) in the sense that a single developer stands no realistic chance of ever completing an implementation of the idea alone.

For this class of open source development the authors essentially require the contributions and gifts of others for the project to even be realizable. I think this is the underlying basis for open source’s move toward a more “community” development model. It has led to open source being viewed by many as requiring a community and a “managed” community at that, to be open source. I think this class of open source is going to be impacted the most by LLM ‘assisted’ development (no matter how much distaste it generates for me and many others), where the hurdles of large scale development are more in reach (seemingly) for solo or very small groups of developers.

The really interesting thing is going to be to see how many of these projects move toward the Carmack ‘gift’ model and look to leave the community-centric model behind as an unnecessary externality.


I think your idealized list of attributes of “open source” is admirable. However, the apprenticeship, comradery, and support are a specific and often sought out feature of some development ‘communities’ for specific software. I’d also say that the ‘loss’ when fixes, updates, optimizations of open source software is not up-streamed is real, but this has very little to do with adopting or promoting the externalities (no matter how laudable) you want to see in certain software’s development.

I personally don’t care about the community, its composition, or its internal structure for a lot of software I use. Even when I’m compiling from source and customizing smaller applications for personal efficiency, I’m not usually interested in being a part of some distributed community centered on that software. Some times I am engaged in the community and appreciate it and the work required to maintain that community. But in either case, the software is “open source”.


I always think about this section when I consider making my personal programming language public. I think if language development was, in 2026, happing the way ESR describes Linux here I might be more persuaded to release. But as it stands now, almost all modern language development is done in the rigid, semi-planned, hierarchical, and “cathedral”-esque development style.

The expectations for language developers is currently huge burden and a massive undertaking, even for small languages that look to publicize at nearly any level. The amount of users that seem to insist on participation in the language’s progress, semantics, or implementation is the vast majority of any online/vocal user base and those same voices seem to view languages with different development models as inherently toys.

I’m sure this is where I am expected to reference Rich Hickey’s comments/post about Clojure development, but I don’t have the link on mobile. But the discussions are legion and legendary at this point.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: