Hacker News new | past | comments | ask | show | jobs | submit login

What makes concepts different from interfaces (Java/C#), traits (Rust) or protocols (Swift)? Is it different enough to need a completely new term?



Warning: // 1990s style generic code: from the article describes me and C++, though I do understand more modern C++ at a basic level, I'm not an expert. You might say I'm.... rusty...

ahem.

One huge difference in general between C++ templates and Rust's generics (I _believe_ Java/C# are more like Rust here, and I'm not sure about Swift) in that C++ templates generally don't check that their calling code actually supports the type that's passed into the template. In other words, the check happens after the template is expanded. (This is the sort example on page 3). Rust's generics system does the opposite: it requires that if you call a method on some generic parameter, that generic parameter is constrained by a trait that has that method. This happens before expansion. So concepts are, in some ways, an attempt to make the C++ system closer to Rust's system. (This is ignoring the actual chronology here, of course: concepts have been in development a long time).

The way "requires" works here is very different than in Rust, as well. In Rust, you define a trait the same way you'd define regular methods. If those methods have a body, then it's used as a default implementation, if it does not, then you must implement that method. The equivalent of "must have an iterator type" is associated types, you add "type Name;" instead of a method signature.

So the equivalent of the "Sequence" type on page 7 would be

  trait Sequence {
      type Value;
      type Iterator<Item=Value>; // Iterator itself has an associated type, Value
    
      fn begin() -> Self::Iterator;
      fn end() -> Self::Iterator;
  }
roughly speaking. I don't think this exactly works, but just to give you some idea of how the syntaxes roughly compare. In general, I know that a Sequence trait in Rust would require higher kinded types or associated type constructors, which Rust does not yet have, and so the concept is probably not directly expressible.

That's my impressions after reading this. I have been meaning to read about concepts for a while, but since I only have so much time, have mostly waited to see how they shake out before really digging in. It's slightly slower going since my C++ isn't spectacular. This post mostly represents my understanding of the differences, I'm not trying to make any judgements here, etc.


Can concepts be used like traits in non-generic code? Which is to say, can it be used as a type name of a variable or function argument? Because there seems to be a lot of overlap between a concept and a pure virtual class, both of which define function signatures. But if concepts are only for templates, and you still have to use pure virtual classes to express traits, that seems like a missed opportunity to me. But I may be missing some nuance here.


> can it be used as a type name of a variable or function argument?

If I understand correctly, placeholders may work for this. This use is described in the "Programming with placeholders" section of the "Introducing concepts" article: https://accu.org/index.php/journals/2157

The remaining articles in Andrew Sutton's C++ concepts series are pretty good, too; so, just in case anyone is interested, here are the links:

- "Defining Concepts" - https://accu.org/index.php/journals/2198

- "Overloading with Concepts" - https://accu.org/index.php/journals/2316


If I understand the first article about placeholders correctly, concepts are indeed intended to be used where you can use ordinary types, just like traits. That looks really cool, if it ends up in the standard.


It's not clear to me; I didn't see it in this pdf but might have missed it.


Concepts are similar to Rust Traits, (I think) Swift Protocols and Haskel Type Classes, but different (significantly more expressive) than Interfaces.

The name has been used in the C++ community since at last mid 90s as it originated from Alex Stephanov work on the STL. Stephanov himself might have used the name even earlier than that. Formalization of concepts which has been attempted at least since the early 00s was influenced by Haskell and in turn did influence both Rust and Swift.


I really love traits in Rust. It's in my opinion the best way to implement interfaces. I'm really thinking about writing a toy language that looks like Rust 99% but without the borrow checker. The ownership thing annoys me. I know it helps creating secure programs but I'd be fine with a language that has Rust syntax/generics/traits/pattern matching with garbage collection. My goal isn't to create a C replacement, but a better Go. Go gets concurrency and syntax right but its type system is shitty. Go is a missed opportunity.


I'm actually a huge fan of their ownership model. I find that in languages where you can't enforce it(Java, etc) architecture tends to suffer. Single owner(with tools to break out when you have to) is a fantastic model.

I feel that lazy ownership gets really gnarly when you start associating large native resources with objects and then can't clearly be sure who's owning a reference to what(see Activity/Context leaking in Android).

All of this stuff is solveable with proper diligence but I prefer my language to enforce it.


> All of this stuff is solveable with proper diligence but I prefer my language to enforce it.

This is why I love Rust in a nutshell (okay, there are actually a lot of reasons, but this is a big one). Given the choice between my ability to write perfectly bug-free code and the compiler to make sure that my code is correct, I'll pick the compiler any day of the week. And that's before taking into account the fact that like most programmers, I have to work with code that's not mine as well.


> All of this stuff is solveable with proper diligence but I prefer my language to enforce it.

Exactly. Everyone trying to defend C always makes this argument, well you just need perfect programmers who write code without mistakes! Why can't everybody just write good C? But some of us live in the real world where those mistakes mean huge vulns.

(Not hating on C in general, just in any security-sensitive context)


Rust's concurrency story is built on top of ownership. Its how Rust prevents data races.


>My goal isn't to create a C replacement, but a better Go. Go gets concurrency and syntax right but its type system is shitty. Go is a missed opportunity.

Have you considered forking Go and replacing the type system? If such an experiment was successful this could be the fabled Go 2.0...


Have you looked at Swift? In some ways, it's a bit like Rust without strict lifetimes Swift has GC (ref counting under the hood) and a fairly expressive type system.


Type classes in Haskell are similarly awesome and where Rust's traits originate from. It's way more flexible and expressive than OO interfaces.


That is more related (not the same) to Java/C# Generics than Interfaces.

That is, it is resolved at compilation time and not at run-time as these that you cited except for some cases in Rust where Traits can be both run-time or compile-time depending on how you use them.

For decades C++ has the equivalent of these, it is called virtual pure classes (we may even consider virtual in general).


Yup, I'm a big fan of how rust does dispatching. It's awesome to not have static/dynamic dispatch tied to the type but the explicit usage.


Besides what the others have replied, C++ already has interfaces, they are pure base classes (virtual if destructors are required).

But those cannot really fulfill the role of concepts in templates.




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

Search: