 So there's a lot of different ways I can take this now, but the one I want to do would be type system. Since that's one of the big things praised about Eta, and well, what exactly do I think about it? There's certain parts of it that are really nice. Take constraints on numeric types. Range constraints, for instance. That is an absolutely fantastic example of something that I think should exist in many other languages, but just simply doesn't. The only thing is, I'm not sure, it should be made as nominative as Eta makes it. What's meant by this is nominative typing systems don't care about what the data actually is. It cares about what name is specifically assigned to it. This means two otherwise incompatible values are incompatible just because of the name difference. I don't feel that's the right way to go about that. In rare cases, there are special semantics that you would like to add on top, and there's other ways you can go about that, and in fact, even despite those ways seeming like they're going to be a little crafty, optimizers completely allied all the overhead that you added, and it just works as expected. Let me get into what I mean by that because I realize that's incredibly vague. An example of this would be, say, an integral percentage type. You have a function that needs to accept a value between 0 and 100, and it uses that value as a percentage, but it doesn't need a fractional part associated with that. So an integer that is acting as a percentage, a bounded percentage at that. Same for whatever reason you don't have a constant that you're going to pass that. Say it's because the user specifies it. Say it's a storefront that the user is searching for anything that's currently at least 20% off, and so it's using that to do that work. You really need to create that as a percentage type, casting it to something that it already is, but just changing its name, or is the point behind the constraint that you're writing saying that, hey, this parameter has to be within this certain value. I think most people would say the latter there, that the point is that you have a parameter of type integer who just happens to be constrained to that specific range, but between it is an extremely strict approach, and the common approach that is shared by C-sharp and others, I'd rather have it. Now I've gotten somewhat close to this kind of thing and C-sharp by utilizing guard clauses, which aren't that necessary in a given its combination of type-based constraints and contracts, but essentially a guard clause is the thing that a contract compiles down to. It's checks overwhelmingly at the very beginning of the code that throw an exception if the check fails, but do nothing if the check passes. You've written these out yourself. A guard clause library does these efficiently by making them into very simple function calls that are procedure calls that just happen to always be inlined. So they function exactly as if you wrote them yourself. They're just quicker to write, especially with tab completion. So I've gotten that kind of behavior through guard clauses, but it's hard to deny that it's better if that's part of the function signature itself, that it's written right in there, and you don't need to add a clause in inside of it. It just exists right there. It compiles down exactly the same. In fact, you could actually implement this using a guard clause library as part of the standard library that it just compiles down to it and utilizes the library as a dependency, but regardless, you want these as part of the actual language, at least many of them. That might not all need to be, but range checks are definitely a big one. Validating that enumeration is, in fact, valid is another big one. There's other examples. Oh, not null is another big one, but I can't really give C-sharp shit on that because they've actually been adding that in now. There's compile time checks for that, and they're going to be adding an even guard clause kind of behavior with C-sharp 9, I believe it should. I believe it's cleared to go into C-sharp 9. Just one additional symbol that you add in addition to the type, and you will get guard clause check behavior. That's still only part of the overall type system, however. It should probably be pretty obvious that I don't really feel like I had this ability to define an entirely new type derived from an existing type, but with a unique name and therefore incompatible is a good idea. One of the big, big problems with that is that functions that you've written that really would work exactly as is because the type, the layout of the type, that structure is exactly identical, but just because its name is different, they don't work anymore. Again, there's sometimes semantic reasons for that, but we will touch up on that, I promise. You can still get those semantics when you truly do need a nominative difference. It's possible, but it's not. Ida does everything wrong. In fact, I think the approach Ida takes as far as object orientation goes is quite a bit closer to what I would consider ideal. It's really no secret that I do not like class-based approaches to object orientation. They're used for a bit too much, and I kind of feel like this regarding Ida and its packages as well. It's just a feature that's doing way too much. Classes are very much like this. Classes are so all-consumely powerful that when you utilize them, you can't, generally speaking, of course, but this strictly applies to C sharp as well, have free-floating functions and procedures. They all have to be methods. Now, you can have static methods as part of a static class. You can have static methods as part of an instance class, in which case you call those the same way, using the instances type as if it was a static class. But you're still left with always being a part of a class. Similarly, because the type declarations are themselves classes, you're always getting class-wide declarations. This means that any function or procedure, any method that accepts one of these types works across the entire class. That's not always what you want. No, I would argue that's what you want in the majority of cases. Maybe it would be better to do a class-wide by default and allow for the specific type to be declared through some specific mechanism, saying that, hey, this function only works on this specific type, even if something is derived from it. But you can't do that in C sharp. You can in Ida. Again, it's a bit tedious to add class to everything, just because it probably should be used for everything. But even still, there are cases where you can write things out, especially when they're directly inherited, but you really don't need to add that class part in because they're just overloads of existing stuff. Similarly, when you're using a class-based approach to typing, or at least objects, you get every part of object-oriented programming immediately right there. Typically speaking, this does depend on the language. C sharp, I think, made a very smart decision different from Java in that unless you explicitly declare a method as virtual or abstract, in which case it has to be virtual, that doesn't happen. That is significant, and I think the right decision to make. Because then, much like with Ida, you don't get the whole vtable thing going on when you don't need it. If you've got a method that is entirely defined as, and it's where it is, it's never going to need to be overridden, it's never going to need anything added to it, it can exist exactly where it is in its entirety and work across anything that derives from it, guaranteed. Those are actually really easy to write. Why pay for the additional overhead? Ida gets that right. C sharp even gets that right, but the majority of class-based object-oriented languages do not get that right. You pay for considerable overhead that you simply don't need. Now this being said, I do want to make a quick aside. The overhead for vtables is immensely lower than the overhead for almost any other type of switching mechanism. The overhead for vtables is, especially on modern processors, lower than the overhead for switching on a tag. This means that in the overwhelming majority of situations in Ida, you actually want to be using a tagged record and not a discriminated record, a variant record rather. Because the overhead is actually lower. That, yeah. Then when you get into things like how de-virtualization can sometimes even be done inside of a jit. Sometimes if you can guarantee that numerous, although otherwise, be virtualized calls made in part of a larger method call will never actually change because, say, they're associated with something that happens to be read only and then for the lifetime of that object, it will never actually change. A application virtual machine, a jit, which you often see with major object-oriented programming languages, can actually write the entire thing down to a single static method. So that's my quick aside. Don't be too afraid of virtual method calls. They're not that bad actually. But if we don't need them, don't use them. I'm glad both Ida and C-Sharp give that choice. But Ida's very clear about giving that choice, similarly. And it's tricky how you would accomplish this and why you would even want to accomplish this. But you can get inheritance or you can get dispatching calls without utilizing inheritance at all. Again, very tricky why you would how to do that and why you would actually want to do that. But there's been at least one situation I've had where that's been justified. And it's possible. With the class-based approach, things are too tightly coupled and that's not possible. You could argue that Ida also allows inheritance, in a way, without actually having to rely on some of these other faculties. But again, I'm not a huge fan of how the variant records work. And just from what I've seen as far as benchmarks go, they're really not all that justified. There's immensely better ways you can go about doing what they do. Now, I do want to say, however, that Ida's lack of constructors, another very common thing that you see in object-oriented programming, I feel like is actually an issue. I feel like there's a lot of declaration things that could be dealt with immensely better had we had constructors. Now, there really wouldn't be anything stopping you from still using specialized functions that act like constructors, returning the constructed object, but using a unique name for a specific purpose. That's fine. And I actually really appreciate that. There's at least two instances now in the .NET world where I have had to rely on static methods within a static class to accomplish that goal, having the actual constructors as internal with internal visibility so that they couldn't be called outside of that, because there was key reasons for the constructor methods having very particular names and being discriminated based on that. Whereas just on constructors and their overloads, it would be so vague and hard to find what you're actually looking for. So that optimization trick thing that I've been mentioning. If you're in a language where you can't just have special syntax for deriving a new numeric type or a new character type or whatever, you can still do it. You can take or you just need new semantics. I've actually run into this issue in IDA as well, where I've needed new semantics, new behaviors on top of the operators that the, if I were to do the traditional derived numeric type, I'd have the default operators and I needed very particular ones with certain ones behaving differently for key reasons. You can do that though. What you do is you define a new record in IDA, just a standard record, nothing going on with it. It's not discriminated, it's not variant, it's not tagged, just a simple record. In the more C++, C++, C sharp world, that would be a struct, not a class, a struct. And what you want to do is have a single field in it of the numeric type that is backing it. From there, you add in all of the APIs you need, all of the operators you need, and so on. This works best when you're working in a language that has implicit conversions. So you can define an implicit conversion from the backing type to the actual type, so that you can still use syntax much like it was just supported in the language itself. Now in the C sharp world, this does require that you do not use the var keyword when declaring variables. You will have to use the full type name. I do that by default anyways. It helps with certain things, especially considering how target typing is being added as a new thing, and there's other situations where it helps. In fact, other than if you're using link queries, I'd recommend against it, and just using var inside of the link queries. But once you've done that, all three of those, you've declared the type with the single field of the backing type, defined your APIs for it, and defined an implicit conversion from the backing type to the target type. You've got it. It will behave exactly as you intended to with the new semantics that you needed. And if you look at the compiled code, there will be no associated overhead with that. Why would there be? You've got a struct with a single field, in which case you have the single field. All the functions and operators you've defined operate actually on that single field. The only thing you've done is defined a special system for the compiler to use, which enforces nominative checking. That's it. You really don't need to do that too much. And I think in a my more ideal kind of programming language, the situations where that's currently required in Anna, where it shouldn't be, like defining a new integer type with standard integer semantics, but that just happens to have a constrained range, I think the better way to do that would actually be to allow at the field or parameter declaration site a range constraint. Say that your parameter is an integer with the specific range. The structure that you just declared, it has this field that is a float with this particular range. That I think is a lot closer to what people generally intend for it. In a few cases, very few cases where you really do need new semantics on a new name. There's already a system for that. There always has been. So we don't need to address that. That's basically all my thoughts for types and the type system. So until the next video, have a good one, guys.