[HN Gopher] Circle C++ with memory safety
___________________________________________________________________
Circle C++ with memory safety
Author : davikr
Score : 103 points
Date : 2024-06-02 12:53 UTC (10 hours ago)
(HTM) web link (www.circle-lang.org)
(TXT) w3m dump (www.circle-lang.org)
| KerrAvon wrote:
| Haven't read through it in enough detail yet to fully understand
| the language changes, but the authors are absolutely correct on
| some basic background that other folks don't always understand:
|
| > Memory-safe languages are predicated on a basic observation of
| human nature: people would rather try something, and only then
| ask for help if it doesn't work. For programming, this means
| developers try to use a library, and only then read the docs if
| they can't get it to work. This has proven very dangerous, since
| appearing to work is not the same as working.
|
| 100% 100% 100%
| dataflow wrote:
| It's an elegant sentence but it's incorrect to say memory save
| languages are predicated on that? Even a room full of C++
| experts who understand this completely and write their code
| strictly based on formal contracts will still eventually write
| memory bugs.
|
| Memory safe languages are just predicated on the memory-safety
| problem being difficult to avoid for humans, because nobody has
| a 0% error rate. They would still be incredibly necessary and
| relevant even if nobody relied on "appears to work" as the
| measure of correctness.
| pornel wrote:
| I think the point is that Rust encodes more rules in its
| interfaces (ownership, lifetimes, thread safety). If you
| misunderstand how a Rust library works, your code most likely
| won't compile instead of silently causing UB.
|
| The rules for safe interfaces are the same for all Rust
| programs, so users know what to expect. Whereas in C++ the
| library author has more to say what usage is supported and
| what isn't (e.g. Rust requires all globals to be thread-safe
| unconditionally, but a C++ library may say it's thread safe
| if you set a config option or it's your problem to
| synchronize access).
| tialaramex wrote:
| You already wrote "100%" enough times, so I'll add that Rust's
| technology, and Rust's culture, still aren't enough, you have
| to really put the work in counteract this very powerful danger.
| Rust's technology + culture should mean you won't blow your
| foot off with this (entirely human) approach in their language,
| but you can definitely give yourself a nasty splinter, destroy
| your customer's data, and a million other dumb things.
|
| For example Rust provides types like core::cmp::Ordering,
| core::time::Duration and core::ops::ControlFlow so sometimes
| your API will be harder to misuse than in might have been
| because you know, your timeout parameter was a Duration, not an
| integer count of seconds (or was it milliseconds?)
|
| But, although eventually Clippy will express doubts, Rust won't
| force you to rewrite that function which took N booleans and
| now after modification takes N+1 booleans, even though all your
| callers are probably a mess of true, false, true, true, false
| undecipherable flag nonsense and a re-factor was called for.
|
| It's surprisingly hard to give new programmers the right
| instincts on this stuff. I'm pretty sure I was terrible (thirty
| years ago) too, so this isn't a humble brag it's just an
| observation.
| maxloh wrote:
| Also, check out Google's in-development Carbon Language, designed
| to address the same issues with a Kotlin-like approach. It's an
| entirely new language that could interoperate with existing C++
| code/library.
|
| https://github.com/carbon-language/carbon-lang
| jjnoakes wrote:
| Does Carbon have any undefined behavior? Some of the wording in
| their goals document suggests that they do/will, but it isn't
| clear to me.
| gumby wrote:
| Unless you solve the halting problem, every language has
| undefined behavior.
| tialaramex wrote:
| Nope.
|
| A language which has _semantic requirements_ and isn 't
| willing to reject programs for which it has been unable to
| determine whether they meet the requirements, will have
| these cases by Rice's Theorem. This is why C++ is a
| complete disaster. C++ _specifically_ does not allow the
| compiler to reject such programs.
|
| You can defuse this like (safe) Rust by just writing
| conservative checking. You will reject some programs you
| would like to have successfully compiled, but that's
| actually OK, programmers who hate it are inspired to
| improve the checking, that's what Rust's "Non-Lexical
| Lifetimes" - mentioned by Sean, are about.
|
| Even more radically, you can be a Special Purpose language
| and just only allow a relatively small subset of possible
| programs, all of which you know are correct, that's why
| WUFFS gets to emit indexing with no runtime bounds miss
| checks - it did all the bounds checks at compile time, all
| source where that wouldn't be possible isn't legal WUFFS
| code.
| mgaunard wrote:
| That is incorrect. A C++ compiler is perfectly allowed to
| reject any program that contains undefined behaviour.
|
| It's just not required to do so.
| leni536 wrote:
| It's allowed to reject programs that will evaluate an
| undefined operation on every possible execution. This is
| pretty much impossible, so no compiler even attempts
| this.
| mgaunard wrote:
| It can replace any path with undefined behaviour to one
| that does std::abort.
| pjmlp wrote:
| It can, but in practice no one does it.
| majoe wrote:
| When you think about it, that's what -fsanitize=undefined
| is doing. It detects undefined behaviour at runtime and
| aborts the program.
| gumby wrote:
| I suppose you can make that assertion by moving the
| goalposts. But Rice's theorem specifically addresses such
| behavior: all turing machines are inherently undecidable
| for all but trivial cases.
|
| You can well argue that Rust may be _better_ than C++ in
| some dimension, just as others can argue that those
| qualities have an unreasonable or intractable cost (note
| that about 20% of all crates resort to `unsafe`). But
| your blanket assertion is not even supported by the
| reference you made.
|
| Also the user is free to tell a C++ compiler to reject
| programs that use many sorts of undefined behavior,
| though indeed nobody would claim that any current
| compiler can identify _all_ such cases. But Rice 's
| theorem says that no Rust compiler could either.
| mike_hock wrote:
| Yes, but it seems that we can't satisfy all reasonable
| real-world use cases this way, or else Rust wouldn't have
| the "unsafe" escape hatch that's actually used by real
| code.
| umanwizard wrote:
| That's not true. The halting problem / Rice's theorem only
| mean that the behavior can't be statically determined by
| the compiler, not that it's undefined.
| Yoric wrote:
| C++ has a specific definition of UB. Most languages don't
| suffer from it, regardless of halting problem.
| Asooka wrote:
| No? The CPU doesn't have undefined behaviour, thus any code
| running on it doesn't have undefined behaviour either.
| There are certain operations whose result is not defined in
| certain states, I think on Intel some SSE operations had
| undefined results, but even then the same order of
| operations will lead to the same result. C/C++ compilers
| generally let you turn off almost all possible undefined
| behaviour assumptions. I think the only one you can't turn
| off is the assumption that a pointer to an object is
| properly aligned, which is understandable - if every
| pointer had to be checked for alignment before every
| access, it would ruin performance.
|
| In general I would be much happier if I could assert to the
| compiler that my data fits certain parameters and it would
| optimise based on these explicit assertions rather than on
| implicit assumptions (undefined behaviour). Those
| assertions could be turned off in the final build if we
| determine they actually impact performance, but I expect
| I'd be able to keep them on all the time.
| fluoridation wrote:
| CPUs do have undefined behavior.
| summerlight wrote:
| My understanding is that if you want a high level of semantic
| compatibility with C++, a certain degree of UB is quite hard
| to avoid. But at least unlike C++, they prefer not to leave
| 100s of different possibilities on the table.
| tialaramex wrote:
| Sean (the author of Circle) is an impressive guy. He started
| pursuing this work at about the same point several of the "C++
| Successor Languages" were created, but although all of them
| _claimed_ to be about solving this problem, especially when first
| announced, they actually don 't have a solution unlike this
| Circle work. Let me briefly enumerate:
|
| Val (now HyLo) says it wants to solve this problem... but it
| doesn't yet have the C++ interop stuff, so, it's just really a
| completely different language nobody uses.
|
| Carbon wants to ship a finished working Carbon language, then
| bolt on safety (somehow) but, only for some things, not data
| races for example, so, you still don't actually have Rust's
| Memory Safety
|
| Cpp2 explicitly says it isn't even interested in solving the
| problem, Herb says if he can produced measurements saying it's
| "safer" somehow that's good enough.
|
| It's interesting how many good ideas from Rust just come along
| free for the ride when you try to do this, do you like
| Destructive Move? Good news, that's how you make this work in
| Rust so that's how Circle does it. Exhaustive Pattern Matching?
| Again, Circles does that for the same reason Rust needs it.
|
| It is certainly true that this is not the Only Possible Way to
| get Safety. It would be profoundly weird if Rust had stumbled
| onto such a thing, but "Let's just copy the thing that worked in
| Rust" is somehow at once the simplest possible plan that could
| work _and_ an astonishing achievement for one man.
| Vt71fcAqt7 wrote:
| >Carbon wants to ship a finished working Carbon language, then
| bolt on safety (somehow) but, only for some things, not data
| races for example, so, you still don't actually have Rust's
| Memory Safety
|
| I'm not sure this is correct. As I understand it, Carbon's plan
| is to add a borrow checker like Rust's.
|
| From a recent talk[0][1] by one of the lead developers:
|
| >Best candidate for C++ is likely similar to Rust's borrow
| checker
|
| [0] slides: https://chandlerc.blog/slides/2023-cppnow-carbon-
| strategy/in...
|
| [1] relevant timestamps:
|
| https://youtube.com/watch?v=1ZTJ9omXOQ0&t=1h31m34s
|
| https://youtube.com/watch?v=1ZTJ9omXOQ0&t=1h9m49s
| tialaramex wrote:
| Chandler has explicitly said that he doesn't see a reason to
| solve data races.
|
| The borrow checker isn't enough on its own to solve this in
| Rust, Sean explains (probably deeper in Circle's
| documentation) that you need to track a new property of types
| which is infectious, Rust does this with the Send and Sync
| traits.
| Vt71fcAqt7 wrote:
| You're right. In fact it was in the previous slide[0] from
| that same talk. Thanks for pointing that out.
|
| [0] https://youtube.com/watch?v=1ZTJ9omXOQ0?t=1h8m19s
| pjmlp wrote:
| Right now, Circle looks like the only Typescript like evolution
| path for existing C++, with a production quality compiler.
|
| Unfortunately WG21 seems to have some issues with any ideas
| coming out from Circle, going back to its early days, and I
| don't see them being willing to adopt Sean's work.
|
| Which is really a pity, as he single handled managed to deliver
| more than whole C++ compiler folks, stuck in endless
| discussions about the philosophical meaning of the word safety.
|
| Maybe at least some vendor in high integrity computing domain
| does adopt his work.
| jokoon wrote:
| > Unfortunately WG21 seems to have some issues with any ideas
| coming out from Circle, going back to its early days, and I
| don't see them being willing to adopt Sean's work.
|
| What reasons? Are those valid?
| pjmlp wrote:
| It was due to the metaprogramming capabilities, due to how
| Circle enables to use full C++ at compile time instead of
| constexpr/constinit/constval, David Sankel has a talk where
| he jokes with the WG21 decision process that was behind it,
|
| "Don't constexpr All the Things", from CppNow 2021,
|
| https://youtu.be/NNU6cbG96M4?t=2045
| fweimer wrote:
| Well, GCC supports -fimplicit-constexpr these days:
| https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-
| Optio...
| wrsh07 wrote:
| I'm very confused by the love for circle - there's a GitHub
| that hasn't been updated for 7 months that doesn't have a
| license.
|
| When I first heard about it, a lot of the ideas seemed
| interesting, but are there users of it?
|
| I think my biggest question is "what is the goal here?"
|
| For carbon they're pretty explicit that it's a research
| prototype. If anything is to come if it, it will need to be
| usable at Google's scale (they have real issues with build
| times, they build from head so abi compatibility isn't
| required, etc)
|
| Herb wasn't really designing cpp2 as a successor language so
| much as a playground to understand what features might make
| sense to propose for adoption in c++.
|
| What is circle? It's more than just some project, but the ideas
| haven't been adopted in cpp and the compiler repository isn't
| being updated
| steveklabnik wrote:
| Circle is not open source, that's correct.
| dwheeler wrote:
| I think that's automatically a dead end, then. People have
| inceasingly abandoned closed source compilers, they create
| a huge risk if the maker decides to stop maintaining it.
| Most languages that people pick up have an open source
| software implementation.
| steveklabnik wrote:
| I think it's more complicated than that, but I agree that
| it's a factor that would give some folks pause for
| currently adopting Circle.
| jay-barronville wrote:
| In most cases, I'd probably agree with your point here,
| but in this case, I think you're wrong. If Circle can
| truly accomplish its stated goals, the value proposition
| of a memory-safe superset of C++ is ginormous. Lots of
| companies with critical software written in C++ won't
| care that Circle isn't open-source as long as it ticks
| all of their boxes (certifications, audits, etc.) and
| they have a strong enterprise support story. This isn't
| your average project.
| reynmorris wrote:
| A lot of coders already do this. My STL replacement has Vector
| and VectorUnsafe. Vector is checked to the hilt for bounds
| safety, stack safety, UB safety, etc. and is slower. But if I
| have a tight loop, I can use VectorUnsafe and just make sure I'm
| being careful, and it has no checks at all.
| jjnoakes wrote:
| Care to share your Vector implementation that is "stack safe"
| and "UB safe"?
| reynmorris wrote:
| It's simple, whether the backing memory is heap or stack,
| it's bounds checked. And overriding all the operators and
| only returning safe types prevents many types of undefined
| behavior.
|
| Of course you can fuck with it enough to make it unsafe, but
| at that point you know exactly what you're doing
| tialaramex wrote:
| Without seeing it, of course it's hard to write examples,
| but typically for this type of thing it turns out that
| "fucking with it" enough to be unsafe is easy to do by
| mistake and so you end up basically saying resorting to
| classic C++ "Nobody will make mistakes" safety which we
| know doesn't work.
|
| In some cases you can even "fuck with it" less than
| std::vector and cause memory unsafety because std::vector
| was implemented by people who've been fucked with before,
| and this "safe" collection maybe was not. Pushing items
| from the collection itself into the collection again when
| it's full is often one way to cause this - the std::vector
| promises this works correctly.
| reynmorris wrote:
| You can assume that the collection doesn't have good
| coverage, but what I'm saying is the constructs in the
| C++ language are there to make it have good coverage.
| Pair this with some Clang sanitation (like banning raw
| pointers) and you'd have to go out of your way to make it
| unsafe.
| umanwizard wrote:
| Does it stop you from writing code like this?
| Vector<int> v {1, 2, 3}; int *p = &v[0];
| v.push_back(4); printf("%d\n", *p); // this is UB
| reynmorris wrote:
| That is not an issue with the safety of the Vector, it is
| an issue with the safety of 'int' and raw pointers. If
| the Vector grows, that pointer points to freed memory.
|
| But yes, in my implementation I have a safe version of
| int called 'i32' which overrides the & operator and
| doesn't allow it to return raw pointers.
| rurban wrote:
| > rust: rigorous memory safety
|
| > circle : unsafe printf
|
| Comeon people, if you allow unsafety, you cannot call your
| language safe. There are safe system languages, but don't lie and
| call unsafe languages safe. Partial safety is not full safety.
| wild_pointer wrote:
| > circle: rigorous memory safety
|
| > rust: unsafe { println!("{}", *r1); }
|
| Comeon people, if you allow unsafety, you cannot call your
| language safe. There are safe system languages, but don't lie
| and call unsafe languages safe. Partial safety is not full
| safety.
| lpapez wrote:
| Unsafe in Rust is not unsafe in the same sense that C/C++ UB
| is unsafe.
|
| Unsafe in Rust means "soundness cannot be statically
| verified, the language will insert runtime checks for you and
| perform a clearly defined action (panic) if they are
| violated".
|
| Much ink has been spilled about "unsafe" in Rust being
| unfortunately named.
| j16sdiz wrote:
| No. No. And no.
|
| > It is the programmer's responsibility when writing unsafe
| code to ensure that any safe code interacting with the
| unsafe code cannot trigger these behaviors.
|
| https://doc.rust-lang.org/reference/behavior-considered-
| unde...
|
| And they transverse
|
| > However, violations of these constraints generally will
| just transitively lead to one of the above problems.
|
| https://doc.rust-lang.org/nomicon/what-unsafe-does.html
| loeg wrote:
| > Unsafe in Rust is not unsafe in the same sense that C/C++
| UB is unsafe. Unsafe in Rust means "soundness cannot be
| statically verified
|
| Right.
|
| But as sibling points out, the rest of your sentence is
| incorrect. The language mostly does not insert additional,
| runtime checks and you are allowed to create UB-level bad
| behavior in unsafe blocks.
| tialaramex wrote:
| Notice that "unsafe" isn't a magic "off" switch, it's just
| super powers, things you would otherwise be forbidden from
| doing are now legal, but things you could have done before
| have the same behaviour - and if everything in an unsafe
| block doesn't need super powers you'll get a compiler warning
| saying the unsafe block you wrote was futile.
|
| So, this only does anything interesting _if_ r1 was a raw
| pointer so that dereferencing it would be prohibited without
| the unsafe block. If it 's just a reference or some smart
| pointer type then that's fine anyway.
| geertj wrote:
| First came across this 2 days ago and found this extremely
| impressive. There's also a YouTube presentation where Sean goes
| over the main features of Circle's C++ memory:
| https://www.youtube.com/watch?v=5Q1awoAwBgQ.
|
| This seems to be adding Rust borrow semantics and borrow checking
| to C++. The delivery vehicle seems to be a C++ compiler that the
| author has been working on for a number of of years. I couldn't
| find a ton more on the background of this.
|
| From a technical perspective this looks promising as a C++
| successor language. The project will have to attract other
| members in the C++ community though.
| secondcoming wrote:
| He's active on the C++ Slack, regularly asking questions about
| the minutiae of the C++ spec. It seems like a massive headache.
| mgaunard wrote:
| Memory-safe languages are IMHO a distraction from making people
| write bug-free code.
|
| There are much more important bugs than memory safety bugs,
| including all sorts of performance bugs.
|
| We need to address the whole spectrum instead of compromising all
| areas in order to tackle niche bugs that only matter in security-
| critical contexts.
| umanwizard wrote:
| It's not true that memory safety bugs only matter in security-
| critical contexts. If a program segfaults, it's going to make
| the user unhappy regardless of security implications.
| Yoric wrote:
| And don't forget that a segfault is the lucky case in matters
| of memory safety bugs. I've worked on many memory safety bugs
| that manifested themselves by silently corrupting data.
| kiitos wrote:
| Memory safety bugs are second only to segfaults in terms of
| importance.
| logicchains wrote:
| In terms of the actual bugs encountered when developing
| modern C++ applications, logic bugs vastly outnumber
| segfaults and memory safety bugs, which are quite rare when
| you're writing business logic.
| erik_seaberg wrote:
| With an MMU, segfaults cause pretty abrupt and obvious
| failures for straying outside the heap or stack. Violating
| memory safety may cause subtle and unpredictable errors even
| in correct functions, which is a lot more dangerous.
| Yoric wrote:
| What kind of niche bugs are you speaking of?
|
| For what it's worth, Rust (and other languages of ML heritage)
| are really good at getting rid of huge categories of bugs, not
| just memory. Not all bugs, of course.
| sunshowers wrote:
| This isn't true in practice.
|
| When you don't have to worry about memory safety, your brain is
| freed up to worry about other kinds of bugs.
|
| The other bit of good news is that the sorts of things Rust
| does to have memory safety also enable the systematic
| elimination of many other kinds of bugs. For example, iterator
| invalidation.
| mgaunard wrote:
| For example, the easiest way to make programs avoid use-
| after-free errors is to never free things.
|
| Would you rather get a program that constantly use all of
| your RAM until you restart it, or one that consistently uses
| very little, but someone crashes in edge cases?
| panstromek wrote:
| The term "Memory safety" also heavily undersells what it
| actually implies in Rust.
| djur wrote:
| > all sorts of performance bugs
|
| A lot of code is written in safe, slow languages that could be
| written in a safe, fast language.
| Guvante wrote:
| This sounds a lot like C++/CLI which has Microsoft backing and
| has a whole .NET sub language.
|
| The problem was even when written together the impedance mismatch
| existed.
| logicchains wrote:
| It's quite ironic that on a page about safety they use an if
| statement without {} braces: if(x % 2)
| vec^.push_back(x); unsafe printf("%d\n", x);
|
| Skipping the braces for single line conditionals in C++ is a lazy
| practice that almost inevitably leads to bugs, like Apple's
| famous goto fail bug: https://www.synopsys.com/blogs/software-
| security/understandi... . While memory bugs are difficult to
| prevent, this particular class of logic bug can be eliminated
| entirely just by always remembering to write two {} around the
| statement, so a language concerned with correctness should
| promote such good practices. if(x % 2){
| vec^.push_back(x); }
| jandrewrogers wrote:
| This is nitpicking style, there are no real safety
| implications. Compilers will happily inform you if the parse is
| ambiguous or code is unreachable.
| logicchains wrote:
| If you write in this style then there's the possibility that
| someone else (or yourself in future) will add a second line,
| like: if(x % 2)
| vec^.push_back(x); do_something_else();
|
| under the mistaken assumption that the second line will also
| only run in the x % 2 case. People make mistakes, this
| particular one can happen, does happen, and has happened many
| times, and the compiler absolutely will not inform or warn
| you, because it doesn't know you intended the second line to
| run in the same if statement as the first (because C++ isn't
| whitespace sensitive). Is ruling out an entire class of bug
| really not worth the effort of just typing two more
| characters?
| j16sdiz wrote:
| Indentation can be fixed with a code formatter in pre
| commit hook.
| dragonwriter wrote:
| Or even an on-save or (and more likely to prevent this
| kind of error in a large file) as-you-type feature in
| your IDE/editor.
| dllthomas wrote:
| Available autoformatting is great, but IIRC the Apple
| issue happened in an automatic merge. Autoformatting
| would still help it be noticed, when someone wondered why
| the formatter changed some bit of the code they hadn't
| touched, but a formatting check in with the automated
| tests would catch it faster.
| throwaway376512 wrote:
| > and the compiler absolutely will not inform or warn you
|
| False.
|
| https://gcc.gnu.org/onlinedocs/gcc/Warning-
| Options.html#inde...
|
| https://clang.llvm.org/docs/DiagnosticsReference.html#wmisl
| e...
| Gibbon1 wrote:
| That feels like a I was learning how to program and this bit me
| and now I'm always scared of it type of bug. I've never seen it
| myself. But then again some of my friends complain about OCD
| coworkers that can't not obsessively remove blank lines from
| code.
|
| I have seen for(size_t i=0; i<n; i++);
| foo(i); if(a>b); a=b;
|
| The famous goto bug was because the assholes had no tests for
| that module.
| jandrewrogers wrote:
| Many of the criticisms are of the C++ standard library design and
| implementation rather than C++ the language per se, particularly
| with respect to undefined behavior. Much of this, in turn, is
| because the C++ standard library is very old and anything new
| added to it must be compatible and interoperable with all of the
| older parts, whether or not it is a good idea. Borrow checking is
| a separate matter.
|
| Modern C++ provides all the tools to build an alternative
| standard library from the ground up with most behaviors and
| interactions being defined and safe. This always seemed like
| lower-hanging fruit for a first attempt than changing the
| language.
|
| C++ is commonly used in contexts where object lifetimes and
| ownership are inherently unknowable at compile-time, safety can
| only be determined at runtime. This is why memory safety
| annotations like 'std::launder' exist in C++. Trying force these
| cases into compile-time memory safety box is a source of much
| friction when using languages like Rust. They handle the 80% case
| where compile-time safety, destructive moves, etc make things
| easy for the developer but then significantly worsen the
| complexity, and therefore safety, of the other 20%. This isn't
| necessarily a bad thing but it intrinsically creates a market for
| C++ which explicitly allows you to handle these cases in a
| reasonable way.
|
| Systems programming is full of edge cases that break tidy
| programming language models. This has to be accommodated
| reasonably in languages that want to wear the mantle of "systems
| language". Zig is an example of a new systems language that does
| this well in my opinion.
| pjmlp wrote:
| Zig is basically Modula-2 with a revamped syntax for C folks,
| plus compile time metaprogramming.
|
| And yes, many of these issues were already solved by other
| system programming languages outside the UNIX linage of
| programming languages.
| 112233 wrote:
| > Modern C++ provides all the tools to build an alternative
| standard library from the ground up with most behaviors and
| interactions being defined and safe.
|
| It also goes to a great lenght to embed standard library into
| base language as deeply as it can, and forces unsafe
| constructs. Just see how many magic types from std namespace
| are emmited by compiler when you use range for, initializers,
| or, worst of all, coroutines. Lambdas with capture by reference
| replace old fashioned dangling pointers with much more modern
| dangling references (you are free to copy lambdas that
| reference local variables :smiling virus with thumbs-up
| emoji:).
|
| There is no way to get "another library", without making it
| not-c++. Those guys cannot even make no-exceptions/no-rtti a
| part of the standard.
| mike_hearn wrote:
| See for example https://suslib.cc/
| pornel wrote:
| I think the "unknowable" lifetimes are C++'s own making.
|
| It's like types in statically vs dynamically typed languages.
| Types are unknowable at compile time when the compiler doesn't
| force them to be static.
|
| And similarly ownership and lifetimes are "dynamically typed"
| in C++, because the compiler doesn't force them to be rigidly
| declared like in Rust.
| orf wrote:
| > C++ is commonly used in contexts where object lifetimes and
| ownership are inherently unknowable at compile-time
|
| What specific contexts are these?
| roca wrote:
| The claim that Rust makes the safety of 20% of code worse
| requires some justification. It is utterly contradictory to my
| experience. Having to do a dynamic check (an array bounds
| check, or `Option::unwrap`) does not make code "less safe".
| legobmw99 wrote:
| I think a challenge to this evolution path is the same as what
| motivated Sutter's cpp2: defaults
|
| I think the premise that a lot of experienced programmers can
| write good C++ is at least somewhat valid. They know to not use
| raw pointers, which APIs to use for bound checking, whatever. The
| issue is that new users don't, and the defaults are bad.
|
| If I have to write #feature on safety in every file, it becomes
| possible to forget. Opting in vs opting out
| ljlolel wrote:
| Who is using Circle C++ in production?
| grumpyprole wrote:
| There was once a time when nobody used C++ in production.
| ljlolel wrote:
| Sorry are you saying nobody is using Circle? Also it seems
| closed source?
| quietbritishjim wrote:
| > There's only one systems-level/non-garbage collected language
| that provides rigorous memory safety. That's the Rust language.
|
| Honest question: what about Ada? It was specifically designed to
| be a safe language for critical systems, and for a while was
| mandated for some military systems. Did the author not consider
| it, or are its protections just not as expansive as Rust's?
| steveklabnik wrote:
| I'm not the author, but there's a few reasons Ada tends to be
| forgotten in these discussions:
|
| Back when Ada was new, people just didn't actually like
| programming in it much. Some did, of course, but many did not.
| This is the reason the Ada Mandate was abandoned.
|
| This led into a situation with a small, walled off community
| that didn't really communicate with the outside world much.
| This has a compounding effect over time.
|
| Ada, while designed for safety critical systems, was not
| actually memory safe until fairly recently. Deallocating memory
| at runtime wasn't, and in my understanding, may only be in the
| presence of SPARK? Hopefully someone can chime in here. Now,
| that fine for the systems Ada tended to be used for, which
| often have either no dynamic allocation or a singular
| allocation at program startup, but for inspiration for other
| language designs, given that it forgoes a hard problem, it's
| not really as useful to those who are trying to solve those
| problems. This doesn't mean Ada is useless for inspiration, but
| for "how do I implement memory safety," it doesn't have many
| unique uses things to offer.
|
| None of this means Ada is a bad language, but these are the
| main contributing factors that I see with regards to your
| specific question.
| pjmlp wrote:
| That is the usual Ada outdated image, just like unsafe code
| blocks in Rust, those Unchecked Deallocation are wrapped in
| safe calls, and since Ada95 there are controlled types,
| allowing for RAII patterns.
|
| Additionally, it is common to use arenas, and many types can
| be dynamically stack allocated with a retry operation in case
| there is not enough space, so that the call can be redone
| with a smaller size.
|
| Memory Management with Ada 2012 from FOSDEM 2016,
|
| https://archive.fosdem.org/2016/schedule/event/ada_memory/
|
| Doesn't go much into SPARK related improvements though, given
| its date.
| steveklabnik wrote:
| Sure, none of that is particularly novel though, so in
| terms of citing it as something specifically to add to the
| conversation, there isn't any real reason.
| quietbritishjim wrote:
| It was the article author's choice to specifically say
| there is no safe systems programming language other than
| Rust. If that is not true then it's worth citing in
| discussion of the article.
| steveklabnik wrote:
| My parent confirmed that deallocating memory is still
| unsafe, even though there are common usage patterns that
| help make sure you're doing it correctly.
| roca wrote:
| How does "redo the call with a smaller size" possibly help
| you? If you could get by with less memory, you should have
| asked for less memory in the first place.
| roca wrote:
| Rust's affine types and borrow checking give safe Rust a
| lot more power than the safe subset of Ada95. A trivial
| getter method that returns a reference (i.e. pointer) to a
| field of its object is safe in Rust, but in Ada95 (and C++
| and most other non-GC languages) in general you can't
| ensure the object outlives the reference.
|
| It is true that Ada has a safe suitable-for-systems-
| programming subset that's much better than most languages.
| I think when people say "Rust is the first safe systems
| programming language" they implicitly mean "that is
| expressive enough for me to replace C++ with".
| tialaramex wrote:
| Ada itself doesn't provide you the same guarantees as Safe
| Rust. You can use SPARK to grant Ada more memory safety
| capabilities. However as a language (rather than comments which
| may or may not be ignored by your Ada compiler) SPARK is from
| 2014, so now we're close to Rust's age.
|
| I assume that the totality of SPARK's guarantees would get you
| to the same place as Rust but I don't know.
|
| A big thing which counts against Ada (and SPARK) in practice is
| that it's not popular. You'll trip over Rust programmers
| everywhere, two of my friends are getting paid to write Rust,
| for completely unrelated companies, unrelated reasons, Rust
| seems like a reasonable fit so those companies picked Rust. You
| don't see that with Ada and SPARK.
| pizlonator wrote:
| Nice to see Sean cite Fil-C, though he does it much more in
| passing than it deserves, considering that Fil-C gives you
| memory-safe C and C++ without requiring any annotations
| whatsoever. He cites it as a sanitizer and references undefined
| behavior, which isn't really how I would describe it (unlike a
| sanitizer, it catches all memory safety bugs, and also unlike a
| sanitizer, it turns a lot of what would have been UB in C++ into
| defined-but-safe behavior). It's a very different approach from
| Sean's.
|
| For example, Circle implies broad overhaul to tooling and
| libraries while Fil-C implies no such thing. Also, Circle is all
| about not using existing compilers on the grounds that they are
| hard to experiment with, while Fil-C is a surgical change to
| clang/LLVM.
|
| The main advantage of Circle over Fil-C is that if you pay the
| cost of that overhaul, you'll get performance that is better than
| what Fil-C could ever do even with a lot of optimization. Not
| obvious to me if that makes it net better, though.
| tialaramex wrote:
| For the performance, there are a _bunch_ of people, some of
| them probably wrong and others definitely right, who believe
| they _need_ the best possible performance from software.
|
| You can sell these people something like Rust because you can
| very often either show why the "better performance" C++ they
| have is wrong (and if they wanted a _wrong_ answer here 's zero
| already, pay me) or sometimes actually worse performance. Not
| every time, but often enough to make a real difference. The
| Circle safety feature should be in the same ballpark.
|
| You can't sell them anything that's just anyway going to have
| worse performance, if you could they'd be writing Java already.
| So that's counting against Fil-C.
| pizlonator wrote:
| Java is a totally different language, so it's not even
| remotely a competitor in this space. Also Java is quite fast,
| even compared to C or Rust.
|
| Fil-C is all about being able to run existing C/C++ code that
| nobody is going to rewrite, not even in a dialect like
| Circle, since the burden of annotations will be too great.
| mike_hearn wrote:
| For existing C++ just using a checked std::vector and Boehm
| GC can get you quite a long way.
| pizlonator wrote:
| Nowhere near to memory safety. There are so many exploits
| left on the table if you do what you say.
|
| Not to mention that Boehm isn't sound on modern C
| compilers. Conservative stack scanning can be foiled by
| optimizations that are valid from the compiler's
| perspective.
| Asooka wrote:
| I'm not sure that last paragraph had to be so toxic. We've had
| enough toxic egos in this industry, we don't need any more. I've
| never heard of this person before, but I do not think I wish to
| be part of his project.
| roca wrote:
| It's an impressive project. One of the key problems for any safe
| language interoperating with C++ (even a safe C++ subset) is that
| you really want to be able to interact with C++ standard library
| types (string, vector etc) safely because they will appear at
| interface boundaries. Circle introduces its own safe standard
| library so I don't see how Circle fares here.
___________________________________________________________________
(page generated 2024-06-02 23:00 UTC)