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

yea, me (pls dont crack)


You could ask for your password to be removed from the list: https://github.com/danielmiessler/SecLists/pull/155


This reminds me a Russian localization of the "Search" bar on some version of Windows 10, which reads something like "Type the prompt to perform search". Also weirdly infantilizing, overly verbose and just plain weird. Had a couple overseas friends ask me a few times why the text on the search bar is so long haha


The old school of bureaucratic verbosity (big words cosplaying precision) dies ever so hard.


This article, although is trying to provide some arguments as for why package managers are "evil", I found the argumentation pretty weak/non-descriptive. It's good if you have the experiences that confirm a specific point of view, but I think these experiences need to be explained in some more detail, because people reading your article may have similar experiences and therefore would find it hard to agree with your points - just like me.

To give a concrete example, you said that javascript does not have a definition of a "package" in its langauge. But what does that really mean, and why should it lead to package manager managers? Because for me, a person who has worked with javascript just a little bit, I know package.json exists and most of the package managers I've worked with agree on what the contents of this file mean. If we limit our understanding to just npm, yarn and probably bun, we don't see how that causes or contributes to the dependency hell problem (sure it exists, but how?).

You said that Go mitigates the issue of dependency hell to some degree, but this is an interesting thought, give it more exploration! Why should something like Go not have this problem not be not as severe as in Javascript?

I may not remember the details of what you said in the article and I would like to check, but currently I can't access the site because it times-out for me.


package.json is a convention, not a language definition, hence package managers may implement "package" management differently; in reality conventions are followed, until they aren't, and that's where hell begins (if something can be abused - it will be); go and odin define package in the language itself as a folder containing source files, and they mitigate many management issues by just having a good standard library, so you wouldn't need as many packages to begin with;


There's something similar I've done programming on linux. I've been working on some things in Odin programming language for a while and there are a ton of changes I've made where the commit contained an executable, because when Odin compiler makes the executable it names it after the main package's directory, without suffix.

Once I complained about this to the community someone suggested a clever gitignore hack:

    *
    !*/
    !*.*
This by default ignores all files, except those that have a suffix and directories. I think this is a useful lesson - if you flip which files you ignore you can change the failure mode from "I accidentally committed a huge file into a repo" to "why isn't it working?". The latter can be pretty much be answered by good CI testing (maybe not always though).


As someone who knows what they're talking about, I'm curious to hear from you, why you consider use-after-free an undefined behavior and not an unspecified behavior instead?

Because as far as I know both undefined behavior and unspecified behavior are the behaviors that aren't specified in the language standard nor the implementation. So what's the difference?


A useful example to consider might be an uninitialized integer in C++

In C++ 98 "int x; foo(x);" is Undefined Behaviour. We said there's an integer named x, then, without initializing x, we passed it as a parameter to the function foo, evaluating the uninitialized value, literally anything is allowed to happen. Program crashes, deletes all the JPEGs large than 15 kilobytes, displays "Boo!" on the screen, anything the program could have done is something it might now do.

In C++ 26 "int x; foo(x);" is merely Erroneous Behaviour. The value of x is Unspecified, but it does have a value. This program might pass any integer to foo -- perhaps your compiler provides a nice compiler setting to choose one, maybe the person building the program picked 814 and so this calls foo(814)

This constraint is an enormous difference. In a sense the Unspecified behaviour is defined, it's just not specific. That variable x will have some integer value, so, maybe zero, or 814, but it can't be a string, or negative infinity, and evaluating it will just do what it would do for its value, whatever that was.

If you don't find that example illuminating enough, try another from a very different language, a data race in Java

Now, in C++ (or Odin though of course Ginger Bill will insist otherwise ad nauseum) the data race is UB. Game over, you lose, anything might happen.

But in Java the data race has Unspecified behaviour. Specifically, when the race happens the variable we raced has some definite value and it's a value it definitely could have had at or before this moment in a sequentially consistent program. So e.g. maybe we're counting clowns, we started from zero, thread A is counting 800 clowns, thread B is counting 600 clowns, but the threads race the same counter, legitimate values we might see at the end include zero all the way through 1400 clowns. -1 isn't possible, 1600 isn't possible, but 1234 is entirely plausible. That's Unspecified behaviour.


Sorry to pop in but I kind of need to clarify my own position even further here:

Odin has "undefined behaviour". SHOCK! HORROR!

The thing I bring up that people think I go "ad nauseum" about (like yourself) is just that the term "undefined behaviour" is in itself "undefined". This is why I try to make as many distinctions about the different kinds of "UB" out there, and even what the "U" means in "UB".

To quote you from earlier:

> ...Ginger Bill will engage in pointless semantic arguments in which he defines away your problem.

Yes... the entire discussion about "UB" is fundamentally a semantic thing, LITERALLY it's an argument about semantics. And if I can "define away [the] problem" in certain cases, then it's literally not Undefined Behaviour. I am not sure what else to say to your point here. The entire discussion around UB is fundamentally a semantics game and always will be. And when people complain about the "semantics game" part, they have not understood the problem in the first place.

Interestingly, the C++26 example you give is a brilliant example of this, it's an Erroneous Behaviour, not necessarily "undefined" or "unspecified".

In the case of race conditions in Odin? This is pretty much a brilliant example of _Unobservable_ behaviour because Odin shares a similar memory model to C, and thus it has to make assumptions. And when the programmer violates certain assumptions, the compiler cannot observe the broken code that easily, and thus it can easily produce unexpected behaviour due to it being unobservable.

I know have said things in passing, but it's a question of what to tell people. A lot of the people who bring up examples of UB bring up are usually TRIVIALLY definable, and things we have probably already defined in Odin (e.g. integer (under|over)flowing, integer division by zero, etc), but when I say what Odin's defined it to, they usually go one of two ways, either "I don't like that definition" or "but I wanted to use these specific passes in the compiler backed to do 'optimizations' with", both of which actually annoys me because I am not discussing with someone serious. In the latter case, "passes" are just algorithms that do things; they are not intrinsically "optimizations". To "optimize" something, you need well defined rules to optimize within, if the rules are ill-defined or arbitrary chosen, then how the heck can anyone call that "optimization"?

> In a language with UB, the use after free is UB. Which explains the nonsensical results. [https://odin.godbolt.org/z/8onn4hxP1]

Even the case of "use after free" that you brought up earlier, it is something which is not a language thing in certain cases, especially when Odin has custom allocators which are defined at the user-level. The language itself knows nothing about of the allocators and how they work, it cannot. So yes, Odin allows for "use after free" but and? We are not enforcing a specific memory allocation strategy at the language level, like other languages. But it could be technically well defined at the algorithm level of that specific allocator. Which leads to my many problem with this discussion: are flawed algorithms/code considered Undefined Behaviour now and thus make the language "UB"? Why is not just shitty code?

And I will literally go... your "nonsensical results" are just... allocator specific behaviour. Yes it's "nonsensical" to you, but Odin isn't C so stop applying its approach to things to it. C has its standard library as part of its spec and defines how `malloc` et al work. Odin doesn't have its core library as part of the spec and never will (base library will to a certain extent with room for implementation specified behaviour for certain defaults, e.g. what is the default `context.allocator` or `context.assertion_failure_proc`, etc).

> Bill's go-to is to blame somebody else...

No... my go-to response is to say where it should be defined, and if it is possible to define at _any_ level (if at all). So even in your case, you are blaming the compiler for something it cannot know if this is undefined or erroneous because it cannot know what you are doing, but the allocator itself could allow for it. `delete` could be a complete no-op and is for many allocators.

It's all about responsibility. What is responsible for what. So if you thin that's "blame", whatever, but that's the question. Is the compiler _responsible_ for "use-after-free" bugs? In some languages, yes. In other languages, no.

> Linux didn't define your programming language, Intel didn't define your programming language, this is your fault Bill.

No but they all put bounds on what is possible in the first place. They literally define the arena the language takes place in, and thus you are subject to their whims, regardless of my feelings about them. No it's not "my fault" anywhere, it's just a thing.

----------

If you want to discuss with me further on this, I'd be happy to do so. Other mediums other than a comment on Hacker News would be preferrable.

----------

P.S. nowhere on the Odin website itself do we say Odin has no "UB" nor even suggest it. So there is no official position on "UB" for Odin anywhere. My comments on Twitter or other social medias should not be taken as official in any way, and be considered closer to "conversation", especially Twitter.

P.P.S. Some of possible meanings of "U": Undefined (i.e. not-defined), Undefinable, Unspecified, Underspecified, Unobservable, Unknown, Erroneous (I know it's not a U), Unimplemented, Ill-Defined (different to Undefined or Underspecified, and again not a U), Defined-At-A-Different-Level (e.g. language, compiler, platform, core library, user's code, etc, and again it's not a U). It's an absolutely mess and things just need to be defined better about what you are talking about.


So funny thing, although I do periodically re-read older material I've written on Hacker News among other places as I've discussed elsewhere, I wouldn't ordinarily look at something like this after it's drifted off my first page until perhaps a month or more have passed. However, this afternoon Youtube's feed suggested I watch a video about exactly this topic by you, and it was pretty obviously a direct response to my comment written a few days after the comment so of course I checked here.

Lets do some high level corrections first, after all you might learn something and if not perhaps others will.

Data Races are not just race conditions. Race conditions are an ordinary part of our lived experience, the example I usually give is putting a cat out of your front door, then walking to the kitchen to close that door too, the cat might race around the outside and enter before you close the other door, and that's a race condition. To defeat this particular race, close other doors (and windows) first. A particularly nasty race condition seen in modern systems is the TOCTOU race, where the programmer checks something is true and later acts on that check but it is perhaps no longer true. Modern Unix systems have several features that exist mainly to prevent TOCTOU races in storage, such as the ...at family of filesystem calls.

Data Races are something much stranger, in my cat analogy Data Races are as if both Alice and Bob were able to pick up the same cat, Alice puts it out in the front garden, Bob puts it in the back garden, at the same time - now where is the cat? The situation is nonsensical even before we try to wrestle with its consequences. But data races are real.

Safe Rust doesn't have Data Races. By the SC/DRF theorem this means Safe Rust is Sequentially Consistent, which is the property humans need to be able to reason about non-trivial concurrent software. Now, you don't have to go this route, the easiest way to get SC is to write serial software, you can't have a data race if your program doesn't have any concurrency. But languages like C or C++ just give up and say well, data races mean UB. That's the default if you have concurrency and can't prove data race freedom. All bets are off, you lose, go home.

The C++ 26 initialization Erroneous Behaviour was precisely my point. You've greatly misunderstood the consequence of it previously being Undefined Behaviour here. Since it makes it clearer to see what's going on lets work entirely with C++ 26 semantics.

In C++ 26 `int k;` gets you a signed integer local variable named k which has some definite value of its type, the compiler has chosen what that value is, maybe it's six. It can't be negative infinity, or pi, or "Odin sucks" none of those are signed integer values. Evaluating k is Erroneous, tooling should (if able) alert you to your mistake, for example by terminating the program but even if it doesn't or can't, there was some definite value (maybe six).

Meanwhile in C+ 26 `int j [[indeterminate]];` gets you a signed local variable named j which does not have any definite value. This was also the consequence your definition of k would have had in earlier versions of C++. Evaluating j is UB. Absolutely anything might happen.

Why would we want this feature? Isn't it just worse? After all, C++ 26 adds a whole language attribute to preserve it, they must have some reason to do so? Rust goes much further, it has an entire type MaybeUninit<T> which exists to enable such dangerous behaviour, so clearly it's valuable enough to go write a lot of code.

Compiler Optimisation. The optimisation passes change your program with the intent to make it faster or smaller. They're obliged to preserve defined semantics when doing this. But they are not obliged to preserve any other properties, after all they were never defined. In your division by zero example, choosing to trap means that Odin has to emit code to check for zero and trap if that's not hardware behaviour. But in a language with UB for division by zero they don't need to emit the check. So hence UB is a potential for compiler optimisation.

You can also sidestep the check with a type system of course. For example Rust doesn't need a division by zero check when the divisor was a NonZero type, those are by definition never zero and so it's safe not to check.

> Why is not just shitty code?

If you prefer, Odin is shitty code. I think that's probably less helpful to anybody who is wondering about it than a more detailed explanation, but if you prefer to write "Odin is shitty code" in Odin's description and FAQ I guess that covers it and you'd see much less criticism on this topic.

But I suspect you don't mean that, which gets to the heart of the issue - which code was shitty? In Rust this is also well defined, and that might unlock for you why so many people like Rust so much. Instead of back-and-forth arguments about whether Jenny's code is wrong for calling Ralph's function with an inappropriate parameter, or whether Ralph's function is wrong for not handling Jenny's call, Rust chooses to nail this down in the language.

Exploring this in more detail led to me writing my first public Rust crate, named misfortunate.

> My comments on Twitter or other social medias should not be taken as official in any way

That's just not how anything works. If you said it then that's what you said.


Watched this video yesterday, and damn, it's really delightful watching experts make content about things they are passionate about. This love and passion is contageous, and even me, who up to this point knew almost nothing about birds has gained a new appreciation and love for these creatures. The fact that they can copy sounds is kinda incredible, and makes me want to listen more to them singing.


I don't think the birds will like the sounds of that :)


Speaking of postgres, you don't even need a function, you can just use RETURNING clause of a modifying query to provide data source for the select:

    select *
    from (
        delete
        from users
        returning id
    )


Except the pain of hitting your pinky on a corner. That one's very real


I really suggest not removing them as they are a great way to estimate the length of the article (which was the first thing I tried to do on your page and had to spend a good minute first looking for a scroll bar, and then holding Page Down key).


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

Search: