Why He's Dropping Rust


  • Dupa

    @dkf said in Why He's Dropping Rust:

    @kt_ said in Why He's Dropping Rust:

    You can be sure that IncludingTax will always return value including tax

    :wtf: says no, you cahn't be sure of that. :headdesk:

    Should've added: if you wrote the app yourself.


  • Discourse touched me in a no-no place

    @kt_ said in Why He's Dropping Rust:

    Should've added: if you wrote the app yourself.

    Still can't be sure. :(


  • Banned

    @dkf said in Why He's Dropping Rust:

    Apparently, the problems could be fixed if all the contained objects were of exactly the same type

    Just put them in a Box. Problem solved. But it requires actually knowing the language you write in...

    Although, I wonder if it's possible to make the Node<T> work for T: ?Sized. Then you could be able to store trait objects in it. It would make node dynamically sized, but since it's stored in Rc anyway, I think it would work in most cases... Need to test it at home.

    @dkf said in Why He's Dropping Rust:

    Because of that, we also need to have operations for extracting a reference to one of the objects from the collection and acting on its real type (or at least a more precise supertype of its real type). This is an operation that can fail at runtime but that cannot be helped without making the code utterly horrific.

    Sadly, Rust has very limited reflections... I think downcasting is possible with Any trait, but last I checked (about a year ago), it was somewhat limited.


  • Discourse touched me in a no-no place

    @Gąska It's probably a good idea to have all the nodes be dynamically-sized anyway, at least for GUIs. GUIs are pretty frequently dynamically-sized things (in terms of memory use, of course) so it doesn't make a lot of sense to get in a panic over trying to pretend otherwise.


  • 🚽 Regular

    @Gąska said in Why He's Dropping Rust:

    So a trait can define abstract functions, but can't access any underlying fields. Let that sink into you. My first reaction to this was "Sorry, what?!".

    I wonder what his reaction was when he learned about Java interfaces. Or maybe he still didn't?

    I think the confusing bit is you can declare and give a default implementation to methods on traits, but you can't even declare fields. That puts Rust traits in a strange place somewhat between abstract classes and pure interfaces.

    @powerlord said in Why He's Dropping Rust:

    As a general rule, you don't want public fields in OOP. The reason being that other parts of the program can make changes to your values when you don't expect it.
    Thus, getters and setters were born.
    Some languages handle this more gracefully than others, such as C#'s properties. C# Properties are a pair of methods that look like fields.

    I agree. I think autoproperties would be a nice feature to add to Rust.
    What I've seen done is creating helper macros along with the trait, macros which can then be used on a trait-implementing class to add an implementation of the required accessors and its backing field.
    While I think it's a relatively good idea, as it makes things more explicit, it's not nearly as convenient as "traditional" field inheritance. It's a pain writing those macros and it leaves open the problem of how you declare private accessors (because trait functions are always public).

    @boomzilla said in Why He's Dropping Rust:

    But let me ask you, what would be a "proper" Rust way to build something like a bunch of different types of widgets like he was talking about? Where Java / C# / C++ class inheritance seems like a straightforward approach?

    I'll be looking at Cursive, Conrod, and of course Servo as references of "how to do proper Rust", if I ever pick up the language seriously.


  • Banned

    @dkf Dynamically Sized Types is actually a name of Rust's feature that lets you hold an object with unknown compile-time size by value in some contexts, without having to do additional microallocations. It's like the C's idiom of having variable-sized array at the end of struct, except it's not just arrays, and it's all automatically checked for correctness. It's been the biggest post-1.0 addition to Rust until MIR got integrated lately.


  • Discourse touched me in a no-no place

    @Gąska said in Why He's Dropping Rust:

    It's like the C's idiom of having variable-sized array at the end of struct, except it's not just arrays

    Of course, if you can do arrays then you can do anything. In C. C is a language that lets you do some truly wicked things. ;)

    Getting a correct model of a GUI requires references to be divorced from ownership, and ownership to be divorced from containment. GUIs also have a tendency to not map smoothly to a call stack; they're usually event-driven with lots of callbacks. These sorts of things tend to break some types of programming abstractions (e.g., C++ RAII doesn't sit nicely once you cease to be strictly structured by a call stack) but they fit the actual problem fairly well; GUIs are asynchronous, and that's the single most difficult thing about them.


  • Banned

    @Zecc said in Why He's Dropping Rust:

    I think the confusing bit is you can declare and give a default implementation to methods on traits, but you can't even declare fields.

    Hmmm, a type which you can derive from that can have methods - with or without default implementation - but cannot have fields... I'm not sure, but I think it exists in Java, and it's called an interface.

    @Zecc said in Why He's Dropping Rust:

    That puts Rust traits in a strange place somewhat between abstract classes and pure interfaces.

    I wonder why you had to specifically say "pure" interfaces, and not just interfaces... Might it be because if you didn't use that word, Rust traits would suddenly stop looking so outlandish?



  • @Gąska said in Why He's Dropping Rust:

    Just put them in a Box. Problem solved. But it requires actually knowing the language you write in...

    No need for Box. Rc and Arc (the Rust equivalent of std::shared_ptr, single-threaded and thread-safe variant) both accept unsized types. And come with Weak complement that is exactly what you need to use for the parent pointer.

    It would then still need some form of dynamically checked interior mutability, but it would probably make most sense to make the objects handle it themselves internally.

    @Gąska said in Why He's Dropping Rust:

    I think downcasting is possible with Any trait, but last I checked (about a year ago), it was somewhat limited.

    Yes; essentially it allows casting only to the type you've initially put in. Well, exactly like std::any. It is difficult to do otherwise with the external virtual method table pointer (in rust objects don't have vptr in them, but instead trait references are composed of pointer to data and pointer to type descriptor).

    ... however, @ben_lubar, I believe go can cast between interfaces without you knowing the actual type, no? And uses the same implementation. So it should be doable. Perhaps, one day...


    Yes, Rust does not have inheritance for code reuse. However, there is a lot of code that does not actually have much use for that. GUI libraries are rather special in that they do. So Rust is not very suitable for GUI libraries yet. It isn't. That does not make it not suitable for many other tasks.

    Also, the Servo (that's the browser that is the main reason why Mozilla sponsors Rust) folks actually do have problem with it! But not so big as to stall their progress and there are still more useful areas to design in Rust than this.


  • 🚽 Regular

    @Gąska said in Why He's Dropping Rust:

    Hmmm, a type which you can derive from that can have methods - with or without default implementation - but cannot have fields... I'm not sure, but I think it exists in Java, and it's called an interface.

    Can interfaces in Java have a default implementation? That's news to me.

    @Gąska said in Why He's Dropping Rust:

    I wonder why you had to specifically say "pure" interfaces, and not just interfaces...

    I didn't have to. I just said it for emphasis. Also to help distinguish from abstract classes — which are "sort of" an interface, in the sense that they can't be instantiated and must be derived from — but really aren't. Abstract classes can have both default implementations and fields, btw.

    This is of course an explanation added in retrospect. The truth is I just wrote like that because it sounded fine in my head.

    @Gąska said in Why He's Dropping Rust:

    Might it be because if you didn't use that word, Rust traits would suddenly stop looking so outlandish?

    Nope. It was not.

    If you want to make this distinction between "pure" and "impure" interfaces then you're just helping my case. Rust traits should decide on whether they are one or the other. The point is it's a bit annoying to allow default method implementations without also allowing default fields.
    But I'd like some clarification on what you classify as an impure interface (or on what you think I'm believing them to be).



  • @Zecc said in Why He's Dropping Rust:

    @Gąska said in Why He's Dropping Rust:

    Hmmm, a type which you can derive from that can have methods - with or without default implementation - but cannot have fields... I'm not sure, but I think it exists in Java, and it's called an interface.

    Can interfaces in Java have a default implementation? That's news to me.

    Since Java 8, yes


  • 🚽 Regular

    Well then, today I learned.



  • @homoBalkanus said in Why He's Dropping Rust:

    Since Java 8, yes

    Is that the version one can't use when developing for Android because it adds new bytecodes and Android does not understand them? Or did they already fix that?


  • Banned

    @Bulb said in Why He's Dropping Rust:

    No need for Box. Rc and Arc (the Rust equivalent of std::shared_ptr, single-threaded and thread-safe variant) both accept unsized types. And come with Weak complement that is exactly what you need to use for the parent pointer.

    But AFAIK it would require traits to be object-safe, which is not always feasible. Unless they relaxed object-safety requirements recently.

    @Zecc said in Why He's Dropping Rust:

    Can interfaces in Java have a default implementation? That's news to me.

    @Zecc said in Why He's Dropping Rust:

    If you want to make this distinction between "pure" and "impure" interfaces then you're just helping my case. Rust traits should decide on whether they are one or the other.

    Why not both?

    @Zecc said in Why He's Dropping Rust:

    The point is it's a bit annoying to allow default method implementations without also allowing default fields.

    Yes, yes it is. But it doesn't make it impossible to work with. Default trait methods can still use trait's other methods.

    @Zecc said in Why He's Dropping Rust:

    But I'd like some clarification on what you classify as an impure interface (or on what you think I'm believing them to be).

    Well, you are the one who introduced this term... Anyway, for me, pure interfaces are those where all methods are pure virtual, and impure are those that have default implementations for some or all of their methods. I don't think it's particularly useful distinction.


  • I survived the hour long Uno hand

    @Gąska said in Why He's Dropping Rust:

    If type A implements trait T, it inherits all public methods and all (0) public fields. You can use A wherever T is needed. If type B also implements T, then everywhere you use A, you could have also used B, and vice versa. That looks very like Liskov substitution to me.

    Oh, so traits are just a fancy name for mixins?

    No, because if type A implements trait T and trait U, and type B only implements trait T, they're not liskov-compatible. There's no derived class here. You've got something more like Duck Typing: if it quacks like a Duck (uses trait Ducklike), you can use it anywhere you need a Duck.

    @Gąska said in Why He's Dropping Rust:

    it's called an interface.

    An interface is nothing more than a contract. You can fulfill contract Ducklike by implementing quack() as format C:\ if you want. There's no implementation there. I'm pretty sure what you have in Rust are mixins: bits of code that can attach to any type to enhance it.



  • @Gąska said in Why He's Dropping Rust:

    But AFAIK it would require traits to be object-safe, which is not always feasible.

    The requirements for Box<Trait>, Rc<Trait> and Arc<Trait> are the same AFAIK. And the trait must be object-safe anyway to use dynamic polymorphism, which is the point here.

    @Yamikuronue said in Why He's Dropping Rust:

    Oh, so traits are just a fancy name for mixins?

    Yes, they are basically a combination of mixins and interfaces. The name also isn't specific to rust; is has been used as mostly synonym to mixin before.


  • I survived the hour long Uno hand

    @Bulb said in Why He's Dropping Rust:

    The name also isn't specific to rust

    Pretty much no terminology is exclusive, I just hadn't heard that one before. I've been living in Javascript land and paying visits to Perl and Python kingdoms from time to time, so that's why probably.



  • @Yamikuronue said in Why He's Dropping Rust:

    Perl

    Perl is where I heard the term first. But given it was in context of Perl 6 design and that Perl 6 has become kinda vaporware...


  • 🚽 Regular

    @Gąska said in Why He's Dropping Rust:

    Anyway, for me, pure interfaces are those where all methods are pure virtual, and impure are those that have default implementations for some or all of their methods. I don't think it's particularly useful distinction.

    Great. I was calling the former interfaces and the latter abstract classes. A rose by any other name.

    @Gąska said in Why He's Dropping Rust:

    Yeah, I didn't know about that. I don't know how I feel about it either. It blurs the distinction between "interfaces" ie "classes with only pure virtual methods" and "abstract classes" ie "classes with non-pure virtual methods ". Why have interfaces then?

    @Gąska said in Why He's Dropping Rust:

    Why not both?

    Sure, as long as the result is a superset of both. As it is now it isn't because of the lack of trait fields.

    @Gąska said in Why He's Dropping Rust:

    @Zecc said in Why He's Dropping Rust:

    The point is it's a bit annoying to allow default method implementations without also allowing default fields.

    Yes, yes it is. But it doesn't make it impossible to work with.

    I could say the same thing about writing assembler, Perl, VB6... But yeah, let's not exaggerate.
    Like I've said above, I'm okay with resorting to helper macros. But it sounds like too much busy work. (I'm not talking out of experience because I can't really claim experience with Rust).

    @Yamikuronue said in Why He's Dropping Rust:

    No, because if type A implements trait T and trait U, and type B only implements trait T, they're not liskov-compatible.

    Just read @Gąska post as saying "then everywhere you use A as a T, you could have also used B"

    @Yamikuronue said in Why He's Dropping Rust:

    I'm pretty sure what you have in Rust are mixins: bits of code that can attach to any type to enhance it.

    Sort of. If you don't give a default implementation, a trait acts more like a requirement for one. One hand giveth, the other taketh away.


    Anyway, writing these posts is getting time-consuming so I'm dropping the conversation.


  • Winner of the 2016 Presidential Election

    @Gąska said in Why He's Dropping Rust:

    Because, let's be honest - if there's a public trivial getter and setter for a private field, this field is effectively public.

    Erm, nope… You can still change the getter and setter to do something completely different if you need to. That's the crucial point.


  • Discourse touched me in a no-no place

    @Yamikuronue said in Why He's Dropping Rust:

    An interface is nothing more than a contract. You can fulfill contract Ducklike by implementing quack() as format C:\ if you want. There's no implementation there.

    Typically that's just because enforcing semantic compatibility of an interface is a stupidly difficult problem. It's semantically-equivalent to the halting problem (or rather to one of its extensions). Because of that, we just have to trust the programmer to get it right when it comes to the deep semantics of interfaces.

    We. Are. So. Doomed.


  • Winner of the 2016 Presidential Election

    @Bulb said in Why He's Dropping Rust:

    Or did they already fix that?

    You can use default methods:

    @Zecc said in Why He's Dropping Rust:

    I don't know how I feel about it either. It blurs the distinction between "interfaces" ie "classes with only pure virtual methods" and "abstract classes" ie "classes with non-pure virtual methods ". Why have interfaces then?

    To avoid multiple inheritance.



  • This is a very interesting thread. I didn't know you could also talk about computers and stuff here!



  • @asdf said in Why He's Dropping Rust:

    @Zecc said in Why He's Dropping Rust:

    I don't know how I feel about it either. It blurs the distinction between "interfaces" ie "classes with only pure virtual methods" and "abstract classes" ie "classes with non-pure virtual methods ". Why have interfaces then?

    To avoid multiple inheritance.

    Except with default implementations you have multiple inheritance again. Thankfully, they actually thought about it and set up rules to avoid ambiguity.

    I guess not much is left for abstract classes except defining private methods.


  • Banned

    @Yamikuronue said in Why He's Dropping Rust:

    Oh, so traits are just a fancy name for mixins?

    I have no idea what mixin is honestly. But I assume that Rust creators, all having Haskell background, are smart guys who know various fancy words related to programming language theory, and if those were mixins, they would call them mixins.

    @Yamikuronue said in Why He's Dropping Rust:

    No, because if type A implements trait T and trait U, and type B only implements trait T, they're not liskov-compatible. There's no derived class here. You've got something more like Duck Typing: if it quacks like a Duck (uses trait Ducklike), you can use it anywhere you need a Duck.

    Oh I see. Whatever. Java's String is not Liskov-compatible either, yet I've never seen anyone complain.

    @Yamikuronue said in Why He's Dropping Rust:

    An interface is nothing more than a contract. You can fulfill contract Ducklike by implementing quack() as format C:\ if you want.

    You can implement Iterator trait in the way that next() calls format C:\ just fine.

    @Yamikuronue said in Why He's Dropping Rust:

    I'm pretty sure what you have in Rust are mixins: bits of code that can attach to any type to enhance it.

    You can use traits both ways. Many traits also use a middle ground - they are interfaces with pure virtual function each type has to wind up itself, but also provide some common methods that are automatically implemented for all types implementing it. For example, Iterator is an interface; everyone has to provide fn next(&mut self) -> Item method, but there are couple dozen other methods (mostly related to iterator adapters and such) that you get for free.

    @Bulb said in Why He's Dropping Rust:

    The requirements for Box<Trait>, Rc<Trait> and Arc<Trait> are the same AFAIK. And the trait must be object-safe anyway to use dynamic polymorphism, which is the point here.

    I see. Cool.


  • Discourse touched me in a no-no place

    @Gąska said in Why He's Dropping Rust:

    Java's String is not Liskov-compatible either

    It is Liskov-compatible… but only with uses that only use the behaviours associated with String or Object. Which is exactly the claim it makes.


  • Banned

    @Zecc said in Why He's Dropping Rust:

    Great. I was calling the former interfaces and the latter abstract classes. A rose by any other name.

    Abstract classes can have fields, interfaces can't.

    @Zecc said in Why He's Dropping Rust:

    Yeah, I didn't know about that. I don't know how I feel about it either. It blurs the distinction between "interfaces" ie "classes with only pure virtual methods" and "abstract classes" ie "classes with non-pure virtual methods ". Why have interfaces then?

    So you can implement more than one at once.

    @Zecc said in Why He's Dropping Rust:

    Sure, as long as the result is a superset of both. As it is now it isn't because of the lack of trait fields.

    I asked why it's bad to have both interfaces that provide default implementations and interfaces that can't provide default implementations in a language. Your answer is that it's fine as long as those interfaces can have fields. :wtf:

    @Zecc said in Why He's Dropping Rust:

    Like I've said above, I'm okay with resorting to helper macros. But it sounds like too much busy work.

    Note that you need those helper macros if and only if you absolutely cannot live without something that at least resembles class inheritance. And many programs can be designed in a way that don't ever require class inheritance.


  • Banned

    @dkf said in Why He's Dropping Rust:

    It is Liskov-compatible…

    Can you derive String?


  • Winner of the 2016 Presidential Election

    @homoBalkanus said in Why He's Dropping Rust:

    Except with default implementations you have multiple inheritance again.

    I still don't understand why some people think multiple inheritance is bad anyway.


  • Discourse touched me in a no-no place

    @Gąska I think you've misunderstood what Liskov-compatibility is all about. It doesn't guarantee that you can construct some arbitrary entity, it just talks about the nature of things once you already have such a thing. Since Java restricts the creation of derived versions of String heavily, strings can only ever be thought of as strings or as basic objects. Any operation you can do on a basic object, you can do on a string. However, it is important to remember that the operation of converting an object to a more derived type is one that is formally permitted to fail; it isn't technically breaking the LSP.


  • kills Dumbledore

    @asdf When I learned C++ it was introduced as "you can do this. But don't, here's why" and the standard diamond inheritance diagram



  • @asdf said in Why He's Dropping Rust:

    I still don't understand why some people think multiple inheritance is bad anyway.

    If you have a root object in the hierarchy like in Java or C#, pretty much every instance of multiple inheritance is a potential diamond problem. So that's one good reason.

    I think the consensus is less "it's bad" and more "it's not worth the hassle".


  • Discourse touched me in a no-no place

    @Maciejasjmj said in Why He's Dropping Rust:

    I think the consensus is less "it's bad" and more "it's not worth the hassle".

    Without MI, class layout is trivial. With MI, it's… less trivial and there's some algorithms involved that make your head ache in some edge cases.



  • @powerlord said in Why He's Dropping Rust:

    As a general rule, you don't want public fields in OOP. The reason being that other parts of the program can make changes to your values when you don't expect it.
    Thus, getters and setters were born.

    Yes, but many - including myself - have argued that they are still a breach of OOP design; a frequently necessary one, one that exists to work around a serious weakness in the OOP paradigm, but still basically breaking or at least bending the rules.

    It all really depends on if you see OOP as 'Abstract Data Types with inheritance and more formally defined information hiding', or if you grasp the 'objects != data' aspect that is the real crux of OOP - inheritance, classes, message passing, methods, those are just the tinsel, it is encapsulation - or more accurately, object atomicity - that OOP is really about.

    To really do OOP, you need to stop thinking of the internal representation of the objects entirely, forget that they have anything to do with data at all and treat them as atomic, ah, objects that are active agents in their own right.

    And the entire idea of using objects to represent data is an abstraction inversion - it simply makes no sense to talk about an 'object-oriented database' or some such absurdity. It is pretty much is a contradiction in terms, and the people who think otherwise don't actual understand OOP.

    A getter is, at best, an instrumentation that can be applied to an object, like a dashboard indicator or a stethoscope; you can get information about the object by probing it or requesting a status check, but in a way it's still kind of awkward and not very in keeping with the real goal of atomicity. It deals with data about the object, which is all too close to looking at objects as data again.

    Setters, on the other hand, are flat-out break from OOP, a direct violation of object atomicity. They exist for two reasons: one, OOP is total crap for general programming, no matter how powerful it is for a handful of critical problem types, so for most problems outside OOP's privileged solution space you need to break the paradigm with abandon if you are going to use it at all; and two, most programmers think Classes == ADTs and treat them accordingly. Classes are ADTs, yes, in terms of implementation, but the whole point of OOP is to forget that there is any implementation and work with the objects as if they were primitives in a physical simulation. If you aren't doing that, then you aren't doing OOP.

    I think part of the problem is that in 1980, when OOP first started making waves, ADTs were unfamiliar to most programmers - the majority of coders were still working in things like FORTRAN, and even C and Pascal programmers tended to avoid doing anything especially complex with struct or record types unless given no alternative. Abstract data types were seen as an academic curiosity; one of the reasons Ada got ridiculed was the emphasis on information hiding, because most programmers didn't see the point of it. ADTs were things people like Niklaus Wirth, Edsger Dijkstra, and Barbara Liskov got worked up about, but to the ordinary programmer they were just hot air.

    When Smalltalk, "C with Classes", and the other first and second generation OOP languages came around, the idea seemed so radical and confusing that the best approximation of it most coders could grasp was "it's ADTs, just done without all the academic BS and with this extra inheritance thing". There was a lot of shouting and kicking and screaming, and people still argued against it right until windowing GUIs started reaching critical importance, at which point people noticed just how good a fit inheritance was for these widget thingies and all the detractors suddenly became fans of what they thought OOP was. So the idea of "Class == ADT" kind of got lodged in a lot of people's minds and became what the next two generations of coders were taught, so no one ever really revisited the idea of what OOP really is. Most programmers today have never seen ADTs in a language that didn't call them classes, so the entire idea that they aren't the same thing doesn't register.


  • Banned

    @dkf said in Why He's Dropping Rust:

    @Gąska I think you've misunderstood what Liskov-compatibility is all about. It doesn't guarantee that you can construct some arbitrary entity, it just talks about the nature of things once you already have such a thing. Since Java restricts the creation of derived versions of String heavily, strings can only ever be thought of as strings or as basic objects. Any operation you can do on a basic object, you can do on a string. However, it is important to remember that the operation of converting an object to a more derived type is one that is formally permitted to fail; it isn't technically breaking the LSP.

    I always understood Liskov's principle as a coding guideline, not language feature. "If you want to use A where B is currently used, make sure all operations and all sequences of operations have the exact same result (as far as the user is concerned) as before the change". In other words, don't break the contract. Array's length shouldn't be different than number of elements in array. Adding at the end should add at the end, not somewhere in the middle. Basically a specific case of the Principle of Least Astonishment. For some reason, @Yamikuronue insists that this kind of thinking cannot be extended to traits because you can't instantiate a trait or something.


  • Considered Harmful

    Disclaimer: all I know about Rust is what I've read in this thread and linked article.

    Rust traits seem to me like if, in C#, you declared an interface and also a set of extension methods to accompany it.

    Sound familiar? It's what LINQ does, almost exactly!



  • @Bulb said in Why He's Dropping Rust:

    ... however, @ben_lubar, I believe go can cast between interfaces without you knowing the actual type, no? And uses the same implementation. So it should be doable. Perhaps, one day...

    Yep. The three most useful Go interfaces have a total of 2 methods (io.Reader, fmt.Stringer, and interface{})


  • Banned

    @ben_lubar sounds like not very useful language 🚎



  • @Jaloopa said in Why He's Dropping Rust:

    @asdf When I learned C++ it was introduced as "you can do this. But don't, here's why" and the standard diamond inheritance diagram

    Of course, C++ also provides virtual inheritance to solve the diamond problem (and more importantly, get a chance to overload another keyword).


  • BINNED

    @ScholRLEA said in Why He's Dropping Rust:

    Bah, I don't expect that Thelema will ever have such problems. A truly academic language doesn't need trivial things like 'a working implementation'.
    Filed Under: that's the sad, sorry truth, and I will probably never get past that

    It's not too late to work on improving Common Lisp or Clojure libraries instead. Just sayin'.



  • @error said in Why He's Dropping Rust:

    Rust traits seem to me like if, in C#, you declared an interface and also a set of extension methods to accompany it.

    Basically. It can also have associated types.

    @error said in Why He's Dropping Rust:

    Sound familiar? It's what LINQ does, almost exactly!

    Except Rust can do a lot more than C#. Because in C# you can define extension methods for already existing type, but they won't be virtual—you can't make the existing type implement a new interface. But that's exactly what traits in Rust do. You can implement them for existing type and if they don't contain generic methods¹, they work as new base types (and so do interfaces in Go).

    On the other hand this should show quite clearly why traits can't have fields: they are added to the data type from outside, so they can't affect its layout.


    ¹ Generic functions can't be dispatched virtually, because they have to be compiled separately for each parameter type. C++ has the same limitation.



  • @antiquarian Not really the point; the goal is to experiment with language design and implementation, not just to design a Lisp. Most of the things I want to try simply wouldn't make sense in either of those languages. My plans involve a radical rethinking of the macro system, the package manager, the executable file format, and the underlying translator, and I have no idea if any of it will work at all; I would basically be redesigning the language even if I were trying to do it within the structure of an existing language, anyway.

    In any case, the things holding me back on Thelema would have just as much impact on anything else I say I want to work on. Maybe more so, since I have both enthusiasm and ego commitment tied into Thelema. Right now I am not able to work on Thelema because I am to psychologically paralyzed to work on anything.


  • Discourse touched me in a no-no place

    @ScholRLEA said in Why He's Dropping Rust:

    Right now I am not able to work on Thelema because I am to psychologically paralyzed to work on anything.

    Well, the only way to fix that is to write some code. It can be terrible code, but write something anyway. I could blather on about a journey of a thousand miles starting with a single step, but ultimately it's about stopping worrying and starting writing. If I'm really feeling stuck, I'll just write something that I want to be code that will work in the end, and then I'll see if I can just write the little bits to make that one concrete thing actually happen; this is good because it is the polar opposite of trying to boil the ocean: you're just trying an idea out and making just that one small thing work (or fail for a good reason).

    Virtually all my big projects had a phase like that, usually at the point where I realise that I've been spinning my wheels badly and that I'm both stuck and bored out of my skull by not making progress.


  • 🚽 Regular

    @ScholRLEA said in Why He's Dropping Rust:

    My plans involve a radical rethinking of [...] the executable file format

    I'd like the executable to contain metadata describing in BNF what arguments it expects and the structure of its output. Possibly allow the format to also specify alternate entry points for the sole purpose of argument autocompletion.

    (require the executable to be trusted first, of course)


  • Discourse touched me in a no-no place

    @Zecc said in Why He's Dropping Rust:

    I'd like the executable to contain metadata describing in BNF what arguments it expects and the structure of its output.

    People have been struggling to describe that sort of thing for years. It's complicated in general. The current group I know of that are working on this have some documents available but I really haven't tried to use their stuff in anger. @ScholRLEA It's probably worth looking at what they're doing as a model even if you ignore the syntax. Syntax is easy to convert between; semantics is not.


  • Winner of the 2016 Presidential Election

    @dkf Interesting. My bachelor thesis was about something similar, only for in-memory data structures that a library expects.


  • BINNED

    @ScholRLEA said in Why He's Dropping Rust:

    Right now I am not able to work on Thelema because I am to psychologically paralyzed to work on anything.

    I still think the world doesn't need another Lisp, but I agree with @dkf on this. In your situation, working on anything will probably be better for you than working on nothing. It will be fun, and it might be therapeutic.


  • Garbage Person

    @Zecc said in Why He's Dropping Rust:

    argument autocompletion.

    TOPS-20 FTW


  • 🚽 Regular

    @Greybeard

    That's before my time.

    For those whose beards aren't grey yet, what was so good about it?


  • Garbage Person

    @Zecc said in Why He's Dropping Rust:

    For those whose beards aren't grey yet, what was so good about it?

    The CLI was extremely user friendly, much more advanced than what you see with modern systems. The Wikipedia entry gives a basic idea, but fails to call out some of the benefits that came from the tight coupling between the CLI and the program.

    The OS would invoke the program when parsing its command line and the program would make system calls to tell the OS what possible things could be input next. So, type a command, some arguments, then "/f?". The instant you type "?", it will print out all switches starting with "F" that can possibly go at that point, then print the command line up to "F" so you can keep typing.

    It's a pity the rest of the system was mostly sh
    %DECSYSTEM-20 NOT RUNNING


Log in to reply