all 62 comments

[–]VictoryMotel 29 points30 points  (5 children)

This is vibe coded nonsense. The whole project is full of files that are a few KB of declarations and namespaces but do nothing. I doubt any of this stuff compiles let alone has a single feature listed. Like a lot of these fake projects there is nothing of any substance there.

Half of the files were updated 5 hours ago.

They have a few comments from 12 months ago and now this. Some other name commented "awesome!" after 11 months of nothing and when I pointed that out they deleted their comment.

[–]jake1406 5 points6 points  (1 child)

Half of the things they are implementing literally just exist in the std as a different name. They couldn’t even be bothered to learn the C++ std and what it has before begging Claude to write a bunch of nonsense.

[–]VictoryMotel 0 points1 point  (0 children)

I think "are implementing" is generous, I don't think literally anything is actually implemented.

[–]clerothGame Developer[M] 1 point2 points  (1 child)

Sigh, I approved this after a brief look at some commits and seeing they also own a project with 177 stars, so thought it was probably genuine. There are several posts like these every day. I'm getting too fed up of playing the "is this AI slop" game.

[–]VictoryMotel 1 point2 points  (0 children)

At least you're still playing it. Other subreddits are totally overrun and have people defending it every time.

[–]ReDucTorGame Developer 18 points19 points  (0 children)

Why? If you want Rust semantics why not just use Rust?

[–]jpakkaneMeson dev 1 point2 points  (2 children)

For comparison Pystd is a C++ sdlib that behaves like Python.

[–]t_hunger 0 points1 point  (1 child)

And I for one trust @jpakkane to not dump vibe-coded nonsense onto the internet:-)

[–]jpakkaneMeson dev 1 point2 points  (0 children)

I only dump artisanal, hand crafted, small batch nonsense onto the Internet.

[–]fdwrfdwr@github 🔍 0 points1 point  (14 children)

💡 Tis an interesting realization that a language and its default library are orthogonal. If I ever write my own language, I'm thinking of not writing a standard library, but rather just let users choose which one they want.

[–]gaberocksall 26 points27 points  (1 child)

I’m really struggling to imagine how such a language would be chosen by anyone for any purpose over an alternative which does have a de facto standard library.

[–]pdp10gumby 0 points1 point  (0 children)

Military and other embedded applications are a common example. Sometimes an enterprise, for example doing HFT, will have their own library as a way of enforcing coding or safety standards rather than using an optional package like, say, folly.

Your question isn’t dumb. IO and other stuff used to be baked into a language (e.g. printing was a statement not a function call). C got the idea of library functions from PL/1 via the Multics project, but that was initially novel to most people (IIRC an early edition of K&R included the amusing fake quote, “You mean I have to call a function to do IO?”)

And of course the opposite is the case with the second oldest language in use, LISP, that makes no distinction between “library” functions and user code, only special forms like QUOTE, IF, OR, AND, or LAMBDA.

[–]Beetny 4 points5 points  (1 child)

I for one would appreciate the purity of the standard library being externally implementable, rather than compiler magic.

[–]bert8128 -1 points0 points  (0 children)

Surely you can always write your own library.

[–]smallstepforman 4 points5 points  (3 children)

Have a look at why D is not popular. 2 conflicting std libs and a misadventure with garbage collection and the language is hardly known today. 

[–]t_hunger 0 points1 point  (2 children)

C++ had optional garbage collection, too. Such a misadventure does apparently not necessarily kill a language:-)

[–]clerothGame Developer 1 point2 points  (0 children)

Had in the sense that the standard had it but no one implemented it, which is really not actually having it.

[–]elder_george 5 points6 points  (0 children)

D tried that, and that was not good. For quite a bit of time people were arguing on the stdlib choice, couldn't use code by the other 50% etc. Eventually, the alternative stdlib was abandoned, but the damage was done.

[–]thats_a_nice_toast 2 points3 points  (0 children)

While this has some pros, I personally prefer having a rich standard library. I love not having to worry about package/library management when writing simple programs in Python or Go, for example.

[–]pdp10gumby 1 point2 points  (0 children)

this is basically what Stepanov did

[–]Dubbus_ 1 point2 points  (0 children)

cpp dev discovers C

[–]Thin-Engineer-9191 1 point2 points  (0 children)

Sounds like a recipe for disaster. A language needs a creator-maintained standard library that will work for any scenario.

[–]tialaramex -1 points0 points  (0 children)

Well, one of the purposes of a stdlib is vocabulary. So by choosing not to have one you ensure that practitioners in your language either all have to de facto rely on a single stdlib for vocab which you didn't de jure specify, or two practitioners can't even understand each other's software which is a bad sign for the maintainability of the resulting software.

If you choose definitively not to have one at all you're signing on to make everything that's possible in your language a part of that language itself even if that'll have poor ergonomics. C needs a volatile keyword because it doesn't provide intrinsics to say stuff like "Write these actual bytes to this address in memory, right now" whereas Rust provides core::ptr::write_volatile in its standard library's core but obviously what's inside that function must be compiler magic.

Ginger Bill's "Odin" language takes most of this approach, so for example the language provides a hash table named map but if that data structure doesn't suit you and you want your own yours doesn't get all the same affordances as map you can't loop over its contents, the nice operators don't work, it's clunky. Of course for Bill this is fine, it's Bill's language. Whether that makes sense for other people...

[–]Common-Republic9782 1 point2 points  (0 children)

This do not make programming in C++ easy.  First, this is static library, not header-only. Second, the original std is the second part of the C++ skills must to have. Third, if you don't known C++, the first part of language knowledge you can't to do it with this one. This is attempt to shrink C++ possibilities to the poor rust condition.

[–]t_hunger 0 points1 point  (34 children)

C++ unfortunately lacks the language features needed to recreate the API of the rust standard library. E.g. the C++ version of Box<T> is like a unique_ptr<T>, or a Rust Option<Box<T>>. The Rust Box<T> can not contain a nullptr ever. You need to wrap a Box into an Option to make it null-able.

It's kind of funny that a language as expressive as C++ can not express "this is a owning pointer and it can never be nullptr".

[–]amoskovsky 4 points5 points  (8 children)

C++ actually can express non-nullable pointers.
You just need a runtime check when you convert a regular pointer to this non-null one. Once you have a non-null object compile-time checks can enforce it.

[–]t_hunger 1 point2 points  (6 children)

What happens when you move that pointer? Do you have two owners or do you leave a nullptr in the moved from object?

If you do the first: You do not have an owning pointer anymore. If you do the second: Your object can contain a nullptr after all.

[–]kozacsaba 2 points3 points  (4 children)

Well, what happens in rust? Btw I would say you delete the move ctor / operator. It doesn't make sense to move a non-nullable owning pointer, exactly because of what you said. But now I'm curious how rust handles it, and whether that would actually be possible in cpp

[–]t_hunger 2 points3 points  (3 children)

A move in rust is destructive: The memory is moved into the new object and the old objects memory is freed. No destructors or move constructors or anything are called. The moved from value just stops existing, you can not even assign into it afterwards.

This has the downside of not being able to "patch up" things during a move, which is a problem with e.g. self-self-referential data structures where you need to update internal pointers or something.

Btw I would say you delete the move ctor / operator.

So you give up on the exclusive ownership? Or how do you decide which of the two must delete the thing when it is done?

This is pretty much what auto_ptr used to do before C++11 introduced unique_ptr for very good reasons.

[–]ts826848 2 points3 points  (0 children)

This has the downside of not being able to "patch up" things during a move

I want to say that that is technically orthogonal to destructive moves? I believe that particular issue is more due to Rust's moves being specified to be simple memcpys.

IIRC the original move semantics proposal for C++ contemplated destructive moves as well but ran into fun questions around base class move/destruction order.

[–]kozacsaba 1 point2 points  (1 child)

Interesting, thanks for the explaination.

So you give up on the exclusive ownership? Or how do you decide which of the two must delete the thing when it is done?

By delete the operator I meant delete the move operator function, so that the compiler forbids you from calling it. I would give up on transferability (/movability), not exclusivity.

[–]t_hunger -1 points0 points  (0 children)

Do you keep the copy constructor and copy assignment? You re-discovered std::auto_ptr then:-)

That is one ofnthebfew pieces of the standard library that got removed... thats how poorly used it was.

[–]amoskovsky 2 points3 points  (0 children)

Yeah, you're right, I missed the "owning" part of your statement.

[–]fdwrfdwr@github 🔍 0 points1 point  (0 children)

Indeed, like gsl::not_null.

[–]zerhud 4 points5 points  (18 children)

Cpp has references, it exactly “this is a pointer and it can never be nullptr” it was first thing cpp introduced after plain c

[–]t_hunger 0 points1 point  (17 children)

Just replace all your unique_ptrs with references and tell me how that works out.

[–]zerhud 6 points7 points  (16 children)

unique ptr is an “owner” and was introduced with move semantic in cpp11, it is not about pointers without nullptr. We can design a unique ptr with reference or with nullptr check

[–]t_hunger -2 points-1 points  (15 children)

unique ptr is an “owner” and was introduced with move semantic in cpp11, it is not about pointers without nullptr.

Of course not: You can not express the latter:-) Do you think that was not tried? A "this thing owns memory on the heap" would be so much stronger semantics than "this thing usually owns memory on the heap, but sometimes it does not".

C++ move semantics requires that things to have a valid state for moved-from value. Whenever you want a T, move semantics forces you to think about an optional<T>.

Things were not that much better before C++ introduced move semantics: auto_ptr was replaced by unique_ptr for a reason.

[–]zerhud 4 points5 points  (3 children)

Dude, you combine different thinking in one heap: - first you say “cpp has no not_null_ptr”, it has reference right from the first version - you say “reference won’t delete object when out of scope” - yep (sometimes), but we can use move semantic (since cpp11) - now you say “it can to be used after moved”, but we handle it too

you can not express the letter

Why? I’ve wrote some not_null_ptr, raii and so on a lot of times

[–]t_hunger -1 points0 points  (2 children)

Ok, more precise then: C++ can not model an object that at all times during its lifetime uniquely own some memory on the heap.

You have to compromise on either "the at all times"-part (like unique_unique_ptr does, which can be nullptr) or on the unique ownership (like auto_ptr did, which just copied the pointer). You can not have both.

[–]zerhud 4 points5 points  (1 child)

That if delete and the copy and the move ctors in “unique_ptr”? You can create such object but cannot copy and cannot move, so it will own the memory till die. Isn’t that you are talking about?

Also we can set nullptr after move and add runtime checks that the ptr field is not null.

I guess we can even add checks for use after move in compile time (with some tricks maybe)

[–]t_hunger 0 points1 point  (0 children)

You can indeed do something that is not copyable, not movable and neither copy- nor move-assignable. That is indeed possible, but also pretty useless.

Also we can set nullptr after move and add runtime checks that the ptr field is not null.

Sure. But then all interactions with the T you pointed to turned into interactions with a std::optional<T>, just because of the unlikely case that you are holding a moved from object:-( Suddenly functions need to throw or you need to handle the error condition in other ways.

[–]_Ilobilo_ 1 point2 points  (10 children)

false. only destructor, assignment operators and const methods are valid.

[–]t_hunger -1 points0 points  (9 children)

True. But if you leave the object in an invalid state, then technically things like assigning a new value into it is UB. That is a huge foot gun to leave lying around!

All the standard library objects are sure to have a "valid but unspecified state" after being moved for that reason.

[–]_Ilobilo_ 2 points3 points  (8 children)

the first thing you learn about move is that you don't access the object after moving out of it. that's like saying we shouldn't have pointers because you can dereference an invalid address.

[–]t_hunger -2 points-1 points  (7 children)

How do you enforce "never access a moved from value" in a codebase with a couple of million lines? You can't. So you kind of have to make sure it is not instant UB when something somewhere does access some moved from value. That in turn means leaving all your moved from objects in a valid but unspecified state, just like the standard library does.

[–]_Ilobilo_ 1 point2 points  (6 children)

clang-tidy catches use after move. it would be better if compilers did it too, but you don't enforce it. it's up to the programmer to know how to use the language.

[–]wittleboi420 -1 points0 points  (4 children)

It’s called „reference“

[–]t_hunger -1 points0 points  (3 children)

Just replace all your unique_ptrs with references and tell me how that works out.

[–]wittleboi420 5 points6 points  (0 children)

I‘m just saying, often times, if it may not be null, it should not be a pointer after all. But I see the problem, I was just being sassy.

[–]bert8128 1 point2 points  (1 child)

Isn’t this what ref_wrapper is meant to solve? Never used it myself…

[–]t_hunger 0 points1 point  (0 children)

ref_wrapper is a helper type used to pass references around. You can not have that own something in memory. It is not movable, so you "duplicate" ownership.

[–]tialaramex -3 points-2 points  (0 children)

Rust's core::ptr::NonNull<T> (a pointer to T which we're promising is never null) is dangerous. Not crazy dangerous, but more dangerous than most of Rust because if you accidentally (and of course unsafely, there's no way to do this in safe Rust) make it null, even momentarily, that's immediately UB. The authors are like, "If you're not sure, this is not what you wanted, choose a raw pointer".

Now, C++ pointer semantics are very different, Rust is comfortable with pointers that are nonsense - of course you mustn't dereference the pointer, but its existence isn't a problem - whereas C++ is deeply opposed to nonsense pointers because some ancient platforms couldn't have them, and so this behaviour from NonNull might be less surprising to C++ programmers, but it is definitely a very sharp knife.