Live data from Hacker News

D 2.069.0 released, compiler automatically ported from C++ to D

dlang.org

121–130 of 131 posts

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#121

Earlier quoted context omitted.

> it's an equivalent set of principles to what you would do in C++ to keep your pointers safe. The things you can prove statically with the borrow checker are a subset of the things that wont trigger UB in C++.

That doesn't contradict what I said. My point was: If you're working on a large C++ codebase you will have to reason roughly about who owns what and where your pointery data is coming from. IME it amounts to (roughly) the same thing as Rust's borrowck rules, just that Rust forces you to think about this a priori, in a clean framework with clear rules, instead of wibbly wobbly, pointy-wointy, ... stuff. The things you…

Your comment has the structure of a well reasoned argument, but it's predicated on falsehoods.

Most large C++ projects do not unnecessarily use reference counting.

Most C++ programmers do not fear using references or pointers because of invalidation.

The Rust compiler does not tell you when it's impossible to satisfy your problem using borrows. In fact it often has false positives requiring borrow gymnastics because it is too primitive.

And your last line is a complete reversal of your previous attitude: Suddenly you are focusing on theory while ignoring that in practice you can not usually break out `unsafe` to solve your borrow problems. In fact it's Rust, not C++, that is more likely to reach for more heavyweight abstractions than necessary because it's not practical to litter unsafe throughout your codebase.

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#122

Earlier quoted context omitted.

That doesn't contradict what I said. My point was: If you're working on a large C++ codebase you will have to reason roughly about who owns what and where your pointery data is coming from. IME it amounts to (roughly) the same thing as Rust's borrowck rules, just that Rust forces you to think about this a priori, in a clean framework with clear rules, instead of wibbly wobbly, pointy-wointy, ... stuff. The things you…

Your comment has the structure of a well reasoned argument, but it's predicated on falsehoods. Most large C++ projects do not unnecessarily use reference counting. Most C++ programmers do not fear using references or pointers because of invalidation. The Rust compiler does not tell you when it's impossible to satisfy your problem using borrows. In fact it often has false positives requiring borrow gymnastics because…

> Most C++ programmers do not fear using references or pointers because of invalidation.

Compared to Rust? I doubt that. Like I said, Rust lets you dance near the line.

This is from experience in various large C++ codebases. I'm not saying people use refcounting a lot, I'm saying it gets used more than Rust.

YMMV though, so it does boil down to a matter of different experiences here. We'll probably have to agree to disagree.

> In fact it often has false positives requiring borrow gymnastics because it is too primitive.

Not really. Aside from non-lexical borrows and a couple other nice-to-have things (but not necessary), the borrow checker is pretty precise for what it tries to prove.

One might argue that the guarantees Rust tries to maintain (one writer or multiple readers for a piece of data) are too primitive. I don't think that's true. Doing a context-sensitive/flow-sensitive analysis might lead to more patterns being allowed but it's hard to scope guarantees when the analysis is interprocedural -- stopping at function boundaries makes sense to me.

> The Rust compiler does not tell you when it's impossible to satisfy your problem using borrows.

It sort of does. If you try to introduce borrows and listen to the suggestions the compiler gives you, and eventually end up nowhere, it's probably not possible to do it that way. It's not perfect, but it's good enough. And it's immune to further changes -- you don't need to design your pointer usage so that it's future-proof; design it however you want, and if a future refactoring introduces a possible use-after-free, fix the compile error.

> And your last line is a complete reversal of your previous attitude: Suddenly you are focusing on theory while ignoring that in practice you can not usually break out `unsafe` to solve your borrow problems.

No, it's not, I'm just pointing out the equivalence. My point was that "The things you can prove statically with the borrow checker are a subset of the things that wont trigger UB in C++." is irrelevant for two reasons -- (a) in practice IMO the things Rust makes you feel safe to do is a superset of what C++ lets you feel safe to do, and (b) if we're going to talk about "all possible things C++ theoretically allows you to do", then you should include unsafe -- you were comparing "safe Rust" with "all C++", which is unfair here, since the entities to be compared for what you're theoretically allowed to do are "all Rust" and "all C++". I focused on a different flaw in your argument, so of course the focus changed. I'm not saying you should use unsafe a lot, I'm saying "what C++ lets you do is equivalent to using unsafe a bit more often in Rust". I don't endorse it, but if you consider "C++ lets you do so many things Rust doesn't" to be a plus point of C++ (I don't), then you should at least be comparing the right things and allowing yourself to use unsafe in Rust too.

> more heavyweight abstractions than necessary

Examples?

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#123

Earlier quoted context omitted.

Your comment has the structure of a well reasoned argument, but it's predicated on falsehoods. Most large C++ projects do not unnecessarily use reference counting. Most C++ programmers do not fear using references or pointers because of invalidation. The Rust compiler does not tell you when it's impossible to satisfy your problem using borrows. In fact it often has false positives requiring borrow gymnastics because…

> Most C++ programmers do not fear using references or pointers because of invalidation. Compared to Rust? I doubt that. Like I said, Rust lets you dance near the line. This is from experience in various large C++ codebases. I'm not saying people use refcounting a lot, I'm saying it gets used more than Rust. YMMV though, so it does boil down to a matter of different experiences here. We'll probably have to agree to d…

> Compared to Rust? I doubt that. Like I said, Rust lets you dance near the line.

Your problem is that you are trying to imagine what happens in the real world rather than just looking at it.

> This is from experience in various large C++ codebases. I'm not saying people use refcounting a lot, I'm saying it gets used more than Rust.

I count 56 imports of Arc and 37 of Rc in servo, would you wager the equivalent parts of chromium or firefox use more ref-counting?

> Not really. Aside from non-lexical borrows and a couple other nice-to-have things (but not necessary), the borrow checker is pretty precise for what it tries to prove.

The problem is that the borrow checker does not look at the function as a whole. You are a slave to the borrow checker, you can only consider other things when it has been satisfied, even if its trivially safe from a whole-function view. Some simple things aren't even expressible at all without non-lexical borrows, no matter what gymnastics you try.

> It sort of does. If you try to introduce borrows and listen to the suggestions the compiler gives you, and eventually end up nowhere, it's probably not possible to do it that way.

That sounds like a terrible workflow that I don't think Rust programmers use in the real world. I think they usually use shared ownership because they know they have shared ownership, not because they gave up on the borrow checker. Any instance of actually resorting to reference counting because of the inability to make the borrow checker happy actually counts against Rust, not for it.

> in practice IMO the things Rust makes you feel safe to do is a superset of what C++ lets you feel safe to do

People routinely do safe things in C++ that would be impossible to express in safe Rust code. You need to let go if this untruth.

> if we're going to talk about "all possible things C++ theoretically allows you to do", then you should include unsafe -- you were comparing "safe Rust" with "all C++", which is unfair here, since the entities to be compared for what you're theoretically allowed to do are "all Rust" and "all C++".

I focused on safe Rust because your argument was that safe Rust is just as powerful as C++, just proved safe statically. This is far from the truth and you refuse to accept the correction. Most people in the Rust community would probably say they accept the loss in power because they prefer absolute safety. This is a very defensive position. It's impressive just how little power Rust gives up in comparison to languages like C#/Java. But to pretend that you actually have more power in Rust due to psychological effects is just zealotry and doesn't reflect how people use C++ in the real world.

> Examples?

Any abstraction that uses dynamic checking that would be considered a bug to actually trigger. Some examples include borrowing a RefCell, random access of iterators, sequential access of certain kinds of iterator adaptors, etc.

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#124

Earlier quoted context omitted.

> Most C++ programmers do not fear using references or pointers because of invalidation. Compared to Rust? I doubt that. Like I said, Rust lets you dance near the line. This is from experience in various large C++ codebases. I'm not saying people use refcounting a lot, I'm saying it gets used more than Rust. YMMV though, so it does boil down to a matter of different experiences here. We'll probably have to agree to d…

> Compared to Rust? I doubt that. Like I said, Rust lets you dance near the line. Your problem is that you are trying to imagine what happens in the real world rather than just looking at it. > This is from experience in various large C++ codebases. I'm not saying people use refcounting a lot, I'm saying it gets used more than Rust. I count 56 imports of Arc and 37 of Rc in servo, would you wager the equivalent parts…

> your argument was that safe Rust is just as powerful as C++, just proved safe statically. This is far from the truth and you refuse to accept the correction.

No, it wasn't; sorry if you thought it was. My argument was that the cognitive overhead of satisfying the borrow checker isn't much different from the cognitive overhead in writing safe C++ code. Perhaps I shouldn't have used the word "equivalent", but that was my original point.

Then you said "The things you can prove statically with the borrow checker are a subset of the things that wont trigger UB in C++.", and I made the theory/in practice distinction, but at no point did I say that was wrong, I just said it wasn't relevant to my point.

Just to be clear, this is the set of things I believe:

- Rust lifetimes/borrowchk have little to no additional cognitive overhead as compared to writing safe code in C++

- Rust lets you approach problems without having to worry so much about safety, which lets you play more fast and loose with references (avoiding unnecessary refcounting, etc)

I agree with you that:

- C++ lets you do more patterns safely than safe Rust lets you compile; and some of these patterns are used often.

- Rust needs to work on improving on things like nonlexical borrows.

I disagree that the above two are major problems or come up often in practice whilst programming Rust. It could be that we've had different experiences whilst programming Rust, however.

> I count 56 imports of Arc and 37 of Rc in servo, would you wager the equivalent parts of chromium or firefox use more ref-counting?

Sure. Firefox has two garbage collectors. Not one. Two. (One of them is Spidermonkey's, which is expected, since Javascript is GCd. The other is for the DOM)

Firefox also has many different types of FooRefCounted base classes, which seem to be used all over the place.

Almost all the Arc is in the highly-parallel layout.

Note that "imports Rc" just means that it deals with an Rc'd value, not necessarily introduces a new Rc'd value. (On the other hand in C++ often you use base classes for Rc, which means that the derived class is Rcd everywhere)

For example, in all of the Servo DOM code, the Page is Rc'd (I forgot the reason, but we don't thrash the refcount too much there), and JS callbacks are Rcd (because of a sticky interaction with the JS runtime, to be expected of something like that), and nothing else. That itself accounts for 20 imports of Rc, even though it's just two kinds of things being Rcd. Arcs are used in code interfacing with the network or layout stack (I think, I haven't looked closely)

> People routinely do safe things in C++ that would be impossible to express in safe Rust code. You need to let go if this untruth.

I agree with this. That's not what I'm saying. I'm not refuting the existence of safe things C++ lets you do that Rust doesn't. I'm just saying that Rust lets you feel safer

> I don't think Rust programmers use in the real world.

Sure, that's not how we program. Because for the vast majority of cases since lifetime annotations exist it's pretty easy (for a Rust programmer) to figure out how to borrow things safely. But there are cases where you're unsure; and it takes very little time to try something out and see what happens.

> Any instance of actually resorting to reference counting because of the inability to make the borrow checker happy actually counts against Rust, not for it.

I don't see refcounting being used to "make the borrow checker happy"; I see it being used in cases where its necessary.

> Some simple things aren't even expressible at all without non-lexical borrows, no matter what gymnastics you try.

I disagree, in my experience it's very rare to hit a situation where you need nonlexical borrows.

> Some examples include borrowing a RefCell

Ah, right. I don't consider refcell too "heavyweight" (and often it can be replaced with the zero-cost Cell), but yes, it does get broken out more than necessary sometimes. I agree with you on that.

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#125

Earlier quoted context omitted.

I'm referring to what people want when they say they want "higher-kinded types" in Rust. That is: the ability to have typeclasses with higher-kinded type parameters. I'm well aware that the formal definition of an HKT is just a type with a higher kind, and that's irrelevant to this discussion.

What certain Rust users want to do with HKT can already be done with D (maybe they're LKT's, loosely-kinded types -- you heard it here first!) or, for example, quite explicitly, C++, without type classes, so it's quite relevant.

No, it's not relevant. When people say they want HKT, what they mean is that they want to create typeclasses that abstract over types of a higher kind and only those types, with a type system that can make those guarantees.

Saying C++ has HKT because it doesn't have typeclasses is like saying Python has all of Haskell's type system features because it doesn't have static types. There's a sort of vacuous sense in which it's true, but it's not a particularly meaningful or interesting thing to say.

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#126

Earlier quoted context omitted.

What certain Rust users want to do with HKT can already be done with D (maybe they're LKT's, loosely-kinded types -- you heard it here first!) or, for example, quite explicitly, C++, without type classes, so it's quite relevant.

No, it's not relevant. When people say they want HKT, what they mean is that they want to create typeclasses that abstract over types of a higher kind and only those types , with a type system that can make those guarantees. Saying C++ has HKT because it doesn't have typeclasses is like saying Python has all of Haskell's type system features because it doesn't have static types. There's a sort of vacuous sense in whi…

We have proof in this very thread that people don't use the term HKT that way. That makes sense, because that's not what the words "higher kinded types" mean.

> Saying C++ has HKT because it doesn't have typeclasses

I didn't say anything like that at all. C++ has HKT, and it doesn't have type classes.

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#127
post #46
post #44

[deleted]

Those sorts of transpilers are usually tailored to a specific project, so it would probably not work on bitcoin-core. Of course if bitcoin-core was committed to moving to D they could fork the transpiler and tailor it to their own code base.

I have no idea what the GP post said, but even if it did work, see patio11's comments (on the internet) on the need to reproduce bitcoin-core's behavior exactly.

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#128

Earlier quoted context omitted.

No, it's not relevant. When people say they want HKT, what they mean is that they want to create typeclasses that abstract over types of a higher kind and only those types , with a type system that can make those guarantees. Saying C++ has HKT because it doesn't have typeclasses is like saying Python has all of Haskell's type system features because it doesn't have static types. There's a sort of vacuous sense in whi…

We have proof in this very thread that people don't use the term HKT that way. That makes sense, because that's not what the words "higher kinded types" mean. > Saying C++ has HKT because it doesn't have typeclasses I didn't say anything like that at all. C++ has HKT, and it doesn't have type classes.

If you consider `template` to be HKT then Rust has this too. Rust macros can be used like C++ templates (minus autoinstantiation) and they can take other macros as parameters. It's not as nice as C++, but ... workable.

Patrick is talking about HKTs which can be typechecked at the source, similar to the rest of Rust generics, when he talks about "they want to create typeclasses that abstract over types of a higher kind and only those types". C++ templates get typechecked at use-time, not instantiation-time, like Rust macros. On the other hand, Rust forces you to constrain types in generics (a la C++ "concepts") so that it typechecks at the source (and then the contract for types being passed into the function is clear in the signature). We don't have higher kinded bounds, though.

HKT, after all, is a comment on bounds. What sort of things are you allowed to substitute for this generic or template parameter?

What seems to be happening here is a difference of opinion on what constitutes a "bound", in the C++ world a "structural" bound (i.e. type vs number vs template) is all you have. In the Rust world this isn't considered a bound, since the bound isn't type-safe. In the Rust world, Haskell world, and most other worlds where the word "kind" is used, a bound is a "type" (typeclass) bound and is type safe -- you can only do operations on the parameter which the bounds let you. Many Rust/Haskell people would consider C++ templates to be a particularly awesome macro system (but not a generics system); since they're structural-bound (like Rust macros); not type-safe.

Really a matter of terminology though.

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#129

Earlier quoted context omitted.

No, it's not relevant. When people say they want HKT, what they mean is that they want to create typeclasses that abstract over types of a higher kind and only those types , with a type system that can make those guarantees. Saying C++ has HKT because it doesn't have typeclasses is like saying Python has all of Haskell's type system features because it doesn't have static types. There's a sort of vacuous sense in whi…

We have proof in this very thread that people don't use the term HKT that way. That makes sense, because that's not what the words "higher kinded types" mean. > Saying C++ has HKT because it doesn't have typeclasses I didn't say anything like that at all. C++ has HKT, and it doesn't have type classes.

[deleted]

Re: D 2.069.0 released, compiler automatically ported from C++ to D

#130

Earlier quoted context omitted.

We have proof in this very thread that people don't use the term HKT that way. That makes sense, because that's not what the words "higher kinded types" mean. > Saying C++ has HKT because it doesn't have typeclasses I didn't say anything like that at all. C++ has HKT, and it doesn't have type classes.

If you consider `template ` to be HKT then Rust has this too. Rust macros can be used like C++ templates (minus autoinstantiation) and they can take other macros as parameters. It's not as nice as C++, but ... workable. Patrick is talking about HKTs which can be typechecked at the source, similar to the rest of Rust generics, when he talks about "they want to create typeclasses that abstract over types of a higher ki…

Exactly. If C++/D have HKT, then so does Rust via its macro system.
Post reply on HN