HNHacker News
TopNewBestAskShowJobs

gingerBill

916 karma · joined March 31, 2014

submissionscomments
gingerBill··on I like Odin
What it is interesting is that the comment never mentions memory safety, only memory management; you just added memory safety into the discuss.

Memory safety and memory management are not equivalent concepts. As I state in another reply (https://news.ycombinator.com/item?id=32629951), you have memory safety and manual memory management. And Odin offers numerous memory safety features as well as being designed around the power of custom allocators.

gingerBill··on I like Odin
Still no. Many problems require manual memory management of which custom allocators aid a lot with. Odin has extensive support for custom allocators and many other things.

RAII may not even make sense within the type system of a language too. Languages with RAII (C++, D, Ada, Rust (through Drop), and Vala) all have higher level constructs such as methods, and many have automatic memory management too (Rust's is automatic but at compile time).

First let's take C++ as an example of a RAII language, RAII has numerous flaws to it:

* In practice (but not necessarily) couples allocation/initialization together meaning that allocations are rarely bulked together and are scope-governed (which can be very poor with performance). (And I know placement `new` exists, but that isn't implicit RAII any more and doesn't solve any of the other problems)

* C++ originally only had copy constructors which usually involved loads of implicit allocations everywhere. This lead to copy-elision optimizations and the introduction of move/ownership semantics as a way to minimize these issues.

* RAII is very implicit to the reader that it is even happening, meaning you cannot just read the code and know what is happening.

* Ctors and dtors usually have to assume to never fail, or require exceptions to handle the failure cases. And not everyone wants, or can even have, software exceptions.

In sum, adding RAII is not a minor thing and to make it even useful without too many flaws requires loads of extra things on top. It's not a simple construct.

I also never said anything about memory safety in my comment. You can have memory safety and manual memory management. The question is what level of safety and in what form. Odin has pretty much all the general memory safety features (bounds checking, Maybe types, distinct types, no pointer arithmetic, default to slices, virtual memory protections, and many more). What Odin does not offer is ownership semantics and lifetime semantics, which is an entire discussion itself which I won't talk about in this already long comment.

gingerBill··on I like Odin
And for you, you clearly don't need manual memory management nor high control over memory, memory layout, and memory access. And that's absolutely fine, but don't criticize something which other people REQUIRE and DESIRE. You cannot "solve memory management" because there isn't just "one problem".

As for RAII, the article itself showcases some of the alternatives Odin has with the `defer` statement and `deferred_*` attributes. So Odin can have many of the aspects of RAII without tying it directly to a data-type/struct/class, which itself as many costs and trade-offs. RAII has loads of problems to it and many other things which are required to solve those problems.

This language is just not for you, and that is absolutely fine! But don't proclaim that it's "ignoring the biggest problem that needs solving" when you are assuming everyone has the same needs, requires, and desires as yourself.

n.b. I am the creator of the Odin programming language; go use a language that will help you solve your problems with your requirements.

gingerBill··on I like Odin
Hello, I am the creator of the Odin programming language, and main architect of the codebase too. Being full of commits labelled "Fix <thing>" is absolutely fine and absolutely clear with all of the context of how the codebase operates.

Many of the things are "Fix #NNN` which means fixing a specific GitHub issue which usually has more information to it or has comments in the code, etc. There are many "Fix typo(s)" commits because I (and others) make a lot of typos; these are usually trivial/single-line fixes. Then it comes to the rest of "Fix ..." commits which are pretty much 1-2 line fixes of minor bugs; with large bugs having multi-line commit messages and many with huge comments within the code to explain everything.

Your metric of the quality of commit messages is not a bad one depending on the codebase, but it cannot be used blindly without knowing how that codebase operates. Especially comparing a mostly centralized codebases (like Odin) to very GNU-style decentralized codebases (all of the examples you gave).

gingerBill··on The Essence of Programming (2021)
> In the approach. Programs, whether the actual instruction set, the ux, the workspace they implement, what have you, are not essential to programming.

And I ask again, where do I ever make any of these claims? I've asked specifically to tell me exactly what I wrote to which you disagree with and you just reply with a strawman.

Regardless, I hope you have a lovely day and thank you for reading the article!

gingerBill··on The Essence of Programming (2021)
Author of the article here:

I quote Rob Pike along with many others in the previous article I wrote (which is linked in the article): "Pragmatism in Programming Proverbs" https://www.gingerbill.org/article/2020/05/31/progamming-pra...

And to be clear, I am making a distinction between the essence of "programming" and the essence of a "program". I agree that with Rob Pike that (and to quote myself) "The purpose of a program is, and ought to be, something that transforms data into other forms of data".

gingerBill··on The Essence of Programming (2021)
> Computational problem can and are being solved with engineering solutions.

I don't even understand what you are trying to say here. What you trying to tell me that I am wrong about? Please tell me exactly what I wrote to which you disagree with.

> Again, this is wrong.

Tell me something where I can do programming (a program, not a programme) which isn't a form of computer? (Be that a digital or analogue computer, i.e. something that _computes_).

gingerBill··on The Essence of Programming (2021)
I think the contention here is the meaning of "craft". I don't think we are actually disagreeing about programming itself but rather how people use that term.
gingerBill··on The Essence of Programming (2021)
Author of the article here:

To clarify what I mean (which I also wrote here: https://news.ycombinator.com/item?id=32507580)

All I ever get from beginners are questions about the "best tool" by which they usually mean "a set of rules and procedures so that I don't have to think about the problem". It's rarely actually finding the "best way" to solve the problem but the "best way" to not have to understand the problem at hand.

Beginners want the shortcuts to solving the problem whilst at the exact same time not even knowing nor understanding what their problem is in the first place.

For more clarification, I highly recommend reading the previous article to this one posted (Pragmatism in Programming Proverbs) to get a better understanding of what I am expressing, since "The Essence of Programming" is a sequel to that article.

gingerBill··on The Essence of Programming (2021)
Author of the article here:

I highly recommend reading the previous article to this one posted (Pragmatism in Programming Proverbs) to get a better understanding of what I am expressing, since "The Essence of Programming" is a sequel to that article. I originally wanted to write the previous article in normal prose article, regarding the topic of "Pragmatism in Programming", however I thought I’d experiment in style by writing in a proverbial style.

> The fact that it happens to execute without bugs and produces the correct output is far less important than the code being readable, comprehensible, and consistent as part of the larger system.

I partially disagree with this. If the code executes without bugs (very rare) and produces the correct output, then that code solves the problem. The next task is to make it readable, comprehensible, and easy to maintain whilst not trying to introduce other bugs.

I recommend reading Casey Muratori's article on "Semantic Compression" https://caseymuratori.com/blog_0015

This article is a good overview of the idea I am trying to express in this reply. It's very important to get things working BUT then actually improve it, don't just stop there!

gingerBill··on The Essence of Programming (2021)
Author of the article here:

All I ever get from beginners are questions about the "best tool" by which they usually mean "a set of rules and procedures so that I don't have to think about the problem".

> The person is trying to ask the question in a way which suggests that he or she does know how to solve the problem in ways that are not so great, and is just looking for a better way.

It's pretty much always the exact opposite since they rarely understand the problem that they are trying to solve to begin with. And that's the issue! They want a "tool" to just do it for them, even if that tool is not even appropriate for the task at hand. And the questions asked are usually in the form of an XY problem: "how can I use X to do Y?". You might be able to bodge the tool X until problem Y is solved but that doesn't even mean it is appropriate to begin with.

For example: I get a lot of questions at the moment about Entity Component Systems (ECS) and asking what is the best way to make one (or which to use) because they want to make a game. But their games don't even require one in the first place since they have such a low number of entities and components that an ECS would probably be detrimental to them in the first place (performance and productively). But to clarify, if the individual wants to just learn about the topic rather than apply it, then I usually recommend them to learn about relational databases first and how they are implemented.

Many people want to use a tool because they've heard someone else (usually a semi-famous programmer or a big company) using it and then following it in a "flash fad" rather than asking whether or not it is even appropriate to use. I will state that this perfectly _rational_ to do by the way since you are trying to outsource wisdom to others that appear to have it. However, programming as a profession is a best 70 years old, and as a result there has been not been enough time for evolutionary selection pressure to reveal the wisdom, so many people (especially beginners0 are effectively walking around following whatever the latest Fad is hoping for wisdom and a set of rules to follow.

> People in this type of field sometimes have a hard time admitting they don't know how to do something. Particularly if they are not such beginners and have a track record of solving problems on their own, which has become part of their self-image.

Humility is a virtue but also a very difficult one possess. For beginners reading: don't be afraid to make mistakes and look foolish. It is a heck of a lot better to look ignorant but honest than to look ignorant but arrogant.

I highly recommend reading the previous article to this one posted (Pragmatism in Programming Proverbs) to get a better understanding of what I am expressing, since "The Essence of Programming" is a sequel to that article.

gingerBill··on The Essence of Programming (2021)
Author of the article here:

"Programming is not a craft." It is a craft and ought to be treated as such. Not doing so leads to the mess in software we have today. Software that is no more complicated than software from 20 years ago but runs 100x-1000x slower than its older counter part. This is the direct result of not understanding what art and craft of programming is and not treating it as such.

I highly recommend reading the previous article to this one posted (Pragmatism in Programming Proverbs) to get a better understanding of what I am expressing, since "The Essence of Programming" is a sequel to that article.

gingerBill··on The Essence of Programming (2021)
Author of the article here:

I completely agree that the essence of a "program" is transforming data. In my previous article which I linked to in the main article, I specifically state "The purpose of a program is, and ought to be, something that transforms data into other forms of data".

But the essence of "programming" is different, and I stand by statement that "Programming is a tool to solve problems that you have in the domain of computers". And this article was an extension of the previous article meaning that taking it out of context has caused this confusion. But the term "programming" embeds the concept of "a program" already: programming produces a program. Programming does not start with hitting the computer with a baseball bat.

gingerBill··on Odin Programming Language
I could add it to the FAQ but it's not frequent enough yet :P
gingerBill··on Odin Programming Language
For slice expressions, the reason for the syntax was done on purpose for the following reasons:

* It's the same syntax as Go and Python, making it familiar to others who have used those languages

* It allows for partial ranges e.g. `x[:]`, `x[:n]`, `x[i:]`

* Partial ranges with the _two_ range expressions (a..<b and a..=b) look awful and are inconsistent: `x[..<]` `x[..=]`, `x[..<n]` `x[..=n]`, `x[i..<]` `x[i..=]`

* You effectively only ever want Python/Go like semantics with slicing because Odin is a 0-index language

* Ranges in Odin are only allowed in two contexts: `cases` and `for in` loops.

As for C-style for loops, they are not obsolete by any stretch and any one who thinks so in think that the compiler can easily optimize a magical complex iterator without any problem. In languages without C-style for loops, you'll see people try to emulate them regardless with variables and a while loop, not just an iterator.

As for syntax, where does it say "don't use it"? I really don't understand why people state things without evidence.

gingerBill··on Odin Programming Language
Absolutely no relation whatsoever.
gingerBill··on Odin Programming Language
This has now been corrected.
gingerBill··on Odin Programming Language
Go is an Garbage Collected language with object oriented features and CSP like concurrency semantics. Odin has none of these built into the language and never will. Go was designed to be a language for web server backends, not general systems level programming such as game development, graphics programming, kernel development, etc.

Odin has numerous features tailored for high performance, modern systems, along with numerous data-oriented things such as SOA data types, array programming, high control over memory layout and memory allocation, custom memory allocators, and much more!

gingerBill··on Odin Programming Language
> Odin is the C alternative for the Joy of Programming.

It is not intent on replacing C since that is not a feasible goal for any language. But making an alternative to C in the high performance modern systems is very much a feasible goal and Odin is such a language.

gingerBill··on The Odin Programming Language
Every "feature" in Odin was added because it has been shown to be good and consistent with the rest of the language.

Slice expressions and range expressions being different was on purpose, as they are very different operations semantically and I wanted to make this clear with the syntax. You can try to unify them but then you lose the abilities to other things which make them distinct which the current syntax offers. It's allow about trade-offs.

Odin does allow you have custom iterators, and C-like for loops do have their uses at times.

`new` returns pointer. `free` takes a pointer. `make` returns a non-pointer data structure which contains internal pointers. `delete` will `free` the internal pointers for specific data structures.

As for the other criticisms, I recommend trying the language itself first to see why they are made. It is not always possible to just do a quick read of a language to understand its decisions.

gingerBill··on Odin Programming Language
It is too much to ask for because Odin is not trying to optimize for beginners nor is it trying to pollute the global namespace with things that require a large runtime. Odin is a systems level programming language and you may not want to use such a feature that uses RTTI in the first place.

Is doing `import "core:fmt"` or something else too much to ask for?

gingerBill··on Looking into Odin and Zig
I agree with you here 100%. It's empirically true that all these things commonly happen. So the question is how do you mitigate these issues, if there are better alternatives? That's what I've been trying to do with the design of Odin, and try to nudge the user away from any of this nonsense whilst still being enjoyable to program in.
gingerBill··on Looking into Odin and Zig
I'm not even saying my approach is "the best" but that there is no silver bullet. Different people and teams will benefit from different styles and approaches. Pluralism in thought and design is better for finding good approaches to things.

If people prefer Odin's approach of Zig's approach or vice versa, that's fine and more power to them.

gingerBill··on Looking into Odin and Zig
Odin language creator here.

Thank you to the author of the article for taking the time to try out both Odin and Zig.

I want to clarify my position as the comments you are commenting on are lacking a little nuance.

For the first one regarding OOM, Odin's allocators all support error values signalling things such as `Out_Of_Memory`, `Invalid_Pointer`, `Invalid_Argument`, and `Mode_Not_Implemented`. So if you you want to handle those error states, there is nothing preventing you from doing so in Odin. However, there are two aspects to my original argument: you should know the constraints of the platform you are on and plan accordingly as it is part of your problem; what happens in the case when you have completely ran out of memory (globally/system-wide)?

> My reaction to that is “640KB is enough for everything”, right?

I've worked on systems with 16KiB and that's just how much you had to deal with. Meaning we had to plan accordingly for what we needed so that we never ran out of memory. The program was heavily tested (both analyzed and empirically) so that we made sure that it ran within the constraint of 16 KiB. On such platforms, `malloc` was never called, and in fact banned.

> I have never had a program cause a system to run out of memory in real software (other than artificial stress tests).

In this comment, I say "program" and not _allocator_ here. I have many allocators that run out of memory _on purpose_. On desktop applications that I have worked on (I know this does not apply to all), if we did run out of memory, the better option is to just crash rather than try to recover. But of course some applications cannot do this, especially when dealing with third-party programs, such as databases (as you state). In those cases, the best you can do is empirically test how much is required and gracefully handle those cases when you do OOM (if possible). That's part of your problem, it's not an external thing. If you can control things, try to.

Minor note: Zig's allocators only return one possible error value `error.OutOfMemory`, whilst Odin has 4 possible error values meaning there is a finer granularity in Odin with its error value system for its allocators.

Onto the second comment you bring up regarding error value handling.

> ...My code, which is calling the service, need to be able to handle any / all of those

Yes. And you should handle them accordingly, and not just in a general "catch all", especially since these are wildly different kinds of failure states.

> ...Odin relies on the multiple return values system. We have seen how good that is with Go. In fact, one of the most common issues with Go is the issue with how much manual work it takes to do proper error handling.

Regarding error value propagation, I needed to clarify my position a little more in that article I was referring to an aggregate set of comments from a GitHub post and not a truly nuanced argument. Odin has the `or_return` operator which allows the user to easily propagate values in code. It is similar to Rust's `?` or Zig's `try` but complements Odin's multiple return values AND does not rely on having a concept of an "error value type".

Demo of `or_return` <https://github.com/odin-lang/Odin/blob/fd256002b3190076bb91e...> And check out Odin's [`core:math/big`](https://github.com/odin-lang/Odin/tree/master/core/math/big) which has big extensive use of the concept.

Even though I added this concept to Odin, I do believe that my general hypotheses are still correct regarding exception-like error value handling. The main points being:

* Error value propagation _ACROSS_ library bounds * _Degenerate states_ due to type erasure or automatic inference * Cultural lack of partial success states

The most important one is the degenerate state issue, where all values can generate to a single type. It appears that you and many others pretty much only want to know if there was an error value or not and then pass that up the stack, writing your code as if it was purely the happy path and then handling any error value. Contrasting with Zig, Zig has a built-in concept of an error value type, and all error values are either inferred `!`, have specific error set, or degenerate to `anyerror`. In practice from what I have seen of many Zig programmers, most people just don't handle error values and just pass them up the stack to a very high place and then pretty much handle any error state as they are all the same degenerate value: "error or not". This problem occurs in Go code too because everyone degenerates to the error interface in practice, therefore it's now equivalent to a fancy boolean.

For error values in Odin, you can use any data type you require for your problem, and even compose many together. It's very common to just use an `enum` or even a boolean, but sometimes you need something more complex or aggregate too. A good example of this is when you need to aggregate different possible error values from multiple different data types. The two common approaches are to make a mapping procedure to convert them to the specific `enum` OR to have a (discriminated) `union` of the `enum`s. This means Odin does not suffer from the degenerate state issue that Zig, Go, and many other languages do suffer from. This is because Odin doesn't have a built-in degenerate type which would be typically used for error values.

One issue with Zig's approach is due to its error value inference system, it's very difficult to know what possible errors values a procedure returns just from __reading__ the code (assuming `!T` or `anyerror!T` is used), you have to compile the code in order to determine that. This may be okay for a single developer, but if you are on a larger team you are now either relying on external documentation (which Zig can provide) or the compiler telling you this. With a specific (error) set this is not a problem because it's explicit to the reader.

Most of the time you are reading code, not writing code.

Odin's type system and feature set is rich enough that you can achieve everything you want _extremely cleanly_. You can many parallels between Odin and Zig: `errdefer` would be akin to `defer if err != nil {` in Odin, `try` would be akin to `or_return`, etc.

n.b. Someone recently wrote an article which is closer to my own position on error value handling (with some of the author's own flair and preferences) here: <http://tuukkapensala.com/files/software_does_not_contain_err...>

Thank you again for writing this article. And as I always say, I highly recommend people try out as many tools (which includes programming languages) as they can to find what are the best tools for your problems!

Regards,

Bill

gingerBill··on The Fatal Flaw of Ownership Semantics
> this particular one leaves a bit of a taste of a maths article written by a crackpot

That gave me a good laugh! I do understand the issue and I am not a brilliant writer in this regard. I was trying to make it understandable to the average programmer but also be at least "correct", and I think I have kind of failed at both in this article. I wanted to make sure that the ideas I was trying to express made sense not just to me or in speech form, but in written form too. I added all those definitions, including "value", because I know so many people who use the terms "value" and "object" interchangeably and assume all values are "objects" in the OOP sense. So I wanted to make a distinction between the two, as I wanted to emphasize the object-ness as the key relationship, not the value-ness.

I am quite interested in how people build mental models of things and how they think about programming in general, but there is very little on the topic currently. And ownership semantics (even the name alone) has a lot of implicit assumptions tagged along to it that I wanted to understand. In sum, "ownership" is the wrong word but oh well, silly history.

And yes, "linear hierarchy" does come from biology. It does mean "linear order" in that sense. That is a much better way of explaining it succinctly.

Interesting you brought up Wirth, since he is one of my idols and that book is absolutely amazing. I always recommend Wirth to beginners wanting to learn how to write compilers.

gingerBill··on The Fatal Flaw of Ownership Semantics
For me, performance is much more critical, and the languages with ownership semantics do not easily allow me to get those performance benefits unless I ignore/bypass the ownership semantics of the language. It's one of the reasons I started my own language, the Odin programming language.

I wanted the ability to have control over memory layout and memory allocations, and be tied to a specific model of how structure and design my program determined by the programming language itself, especially ideas which have yet to prove themselves as being "good" (by whatever metric).

gingerBill··on The Fatal Flaw of Ownership Semantics
A "linear graph" is effectively a graph with no cycles in it, i.e. a basic tree.

All hierarchies can be described using graphs, and hierarchy is a relationship between different things in that graph through some dominating aspect (whatever that might be). A "linear hierarchy" is a hierarchy with no overlapping parts, no cycles, and a unique way to traverse up the hierarchy, e.g. you father is your son is not allowed, a node cannot be part of multiple hierarchies, a node has two parents which share a common ancestor, etc.

I am not sure why you brought up my "Value" definition, that was a little random.

> Unless you equate the graphs with their traverses?

I mostly am because data structures on their own without algorithms are useless things. Type systems try to encode information about the values effectively restricting what algorithms can do to them. Ownership semantics are another aspect of the type system of some languages which encodes a responsibility dependency graph to values. This means it explicitly restricts what data structures can be like _by default_. It encourages linear data structures, where the dependency between the values can be model through linear logic. This is why something as basic as a linked list is difficult to implement in languages designed around ownership semantics. It is of course possible but either requires restricting what the linked lists can do, or doing something to bypass the ownership semantics entirely.

gingerBill··on The Fatal Flaw of Ownership Semantics
> it’s not just about finding a way to cope with the constraints it imposes; it’s also about thriving within the constraints it imposes

This is an extremely important point! Most people try to make a language act like another language, rather than try and embrace how it does things. "When in Rome(, do as the Romans do)"

It's like when people try and make C into another language by abusing the macro system, you get a horrible mess compared to if you embraced what the language likes to do normally.

Personally, I think Rust's memory model is quite high level, and coupled with its ownership semantics, I cannot do many things such as custom allocators. (Not a singular custom global allocator)

gingerBill··on The Fatal Flaw of Ownership Semantics
I absolute agree with you, but you already knew this. I think the terms "ownership" and "move" are confusing and what it really is "responsibility".

> ...ownership/move semantics is fundamentally based around the _responsibilities of values_ by tracking value usage. > ... > If we were to call Ownership Semantics a paradigm, it would be the orientation around the responsibility of values in a hierarchical fashion, placing emphasis on this system of responsibility, shifting focus from data structures and algorithms.

I am not a brilliant writer (which I already knew, even though loads of people have commented on that), but I was trying to get an idea I had in my head onto paper. I wanted to explain that this abstraction is not as good as it is being advertized and does have its limitations. It's not a criticism of the concept, but its application to a bunch of problems.

gingerBill··on The Fatal Flaw of Ownership Semantics
I have noticed loads of people are commenting on the "fatal flaw" bit of the title. It is a click-bait title, and if it was anything else, no one would be commenting on the post in the first place. "A Critique of Ownership Semantics" is less interesting to click on than "The Fatal Flaw of Ownership Semantics".
← PreviousPage 7 of 9Next →