Is struct inheritance implemented yet?

Can I make a struct inherit from another? For example can I take an Array that allows all types and make an inherited array that specializes in a singular type? What I imagine doing (gets a compiler issue):
struct Example[T: AnyType]:
var data: T

fn __init__(inout self, info: T) -> None:
self.data = info

struct InheritedExample[T: Int](Example):
# The variable data and __init__ use T so it should be overwritten
# and prevent unnecessary boilerplate
pass
struct Example[T: AnyType]:
var data: T

fn __init__(inout self, info: T) -> None:
self.data = info

struct InheritedExample[T: Int](Example):
# The variable data and __init__ use T so it should be overwritten
# and prevent unnecessary boilerplate
pass
15 Replies
Jack Clayton
Jack Clayton15mo ago
Not yet, that’ll be worked on after traits and lifetimes are in. Will probably look like Swift extensions: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/extensions/
TeamPuzel
TeamPuzel15mo ago
@Three chickens in the green bag Because Mojo will approach abstraction very similarly to Swift I would really recommend you to watch WWDC 2015 session 408 which explains how protocols and extensions differ from traditional inheritance. Sadly Apple removed it from their website but you can find it if you google for it! In your example specifically, there would not be an Array base class, rather multiple protocols describing different properties collections may have - since you don't have the problems of multiple inheritance this is much more flexible, you can express something that is both a collection and something else, or even make something into a collection retroactively by proving it satisfies the requirements in an extension. Then to make a specialized collection, like an Array, you just have to prove it has the properties of one and you get all the methods like map filter reduce for free. This is very much like Haskell where you try to make your implementations as generic as possible. Your code example would look like this:
// Requirements for an example
protocol Example<T> {
var data: T { get set }
init(info: T)
}

// Default implementation
// Can be written only in terms of other requirements
extension Example {
init(info: T) { self.data = info }
}

// You still need to explicitly implement properties
struct InheritedExample: Example<T> {
var data: T
}
// Requirements for an example
protocol Example<T> {
var data: T { get set }
init(info: T)
}

// Default implementation
// Can be written only in terms of other requirements
extension Example {
init(info: T) { self.data = info }
}

// You still need to explicitly implement properties
struct InheritedExample: Example<T> {
var data: T
}
This is very different from inheritance because you may not "inherit" properties, only require them, but you can still have default method implementations. It feels a bit more limiting at first but eventually turns out to be a lot more powerful once you understand it. Protocols themselves can inherit from other protocols (My example is not valid Swift because it's a bit more complicated to use generics on protocols)
Moosems / Three chickens
And could I make the Inherited Example take all the precious protocols but now narrow it down only to Ints?
TeamPuzel
TeamPuzel15mo ago
Yeah though at least in Swift and Rust this is done with an "associated type" not generics
guidorice
guidorice15mo ago
would love to get a link to that wwdc session. did some searches but could not turn it up.
ModularBot
ModularBot15mo ago
Congrats @guidorice, you just advanced to level 5!
TeamPuzel
TeamPuzel15mo ago
you would just replace T with Int in the implemented example and Swift would infer it I will not use init as this makes this really complex, because the protocol does not know all properties ahead of time (so it's difficult to make default implementations, no super.init() here as it must be known at compile time) but it actually looks like this:
protocol Example {
associatedtype T
var data: T { get set }
func returnsData() -> T
}

extension Example {
func returnsData() -> T { self.data }
}

struct InheritedExample: Example {
var data: Int
}
protocol Example {
associatedtype T
var data: T { get set }
func returnsData() -> T
}

extension Example {
func returnsData() -> T { self.data }
}

struct InheritedExample: Example {
var data: Int
}
This compiles, it just knows you used Int InheritedExample will get a returnsData() -> Int automatically It's the first search on google for me I hope Apple doesn't take this down, someone put it here https://www.youtube.com/watch?v=p3zo4ptMBiQ
guidorice
guidorice15mo ago
thanks @TeamPuzel 👍
Moosems / Three chickens
So what would this look like when mojo-fied?
TeamPuzel
TeamPuzel15mo ago
ok, I'll try to make up the syntax ;)
Moosems / Three chickens
Thank you man!
TeamPuzel
TeamPuzel15mo ago
If Mojo uses parameters:
protocol Example[T: AnyType]:
var(get set) data: T
fn returns_data(self) -> T

extension Example:
fn returns_data(self) -> T: return self.data

struct InheritedExample(Example[Int]):
var data: Int
protocol Example[T: AnyType]:
var(get set) data: T
fn returns_data(self) -> T

extension Example:
fn returns_data(self) -> T: return self.data

struct InheritedExample(Example[Int]):
var data: Int
if mojo uses associated types:
protocol Example:
type: T
var(get set) data: T
fn returns_data(self) -> T

extension Example:
fn returns_data(self) -> T: return self.data

struct InheritedExample(Example):
var data: Int
protocol Example:
type: T
var(get set) data: T
fn returns_data(self) -> T

extension Example:
fn returns_data(self) -> T: return self.data

struct InheritedExample(Example):
var data: Int
Not sure how you would demand get or get set because I don't believe Mojo has computed properties right now get set means the protocol demands mutable access get means the protocol doesn't care (it can be either) That's probably why it was done for Swift, it's not exactly let and var.
Moosems / Three chickens
I like the parameterized example.
TeamPuzel
TeamPuzel15mo ago
From what I understand there's a meaningful difference between the two but I'm not sure I can explain it without making a mistake I think it comes up when you have a more complicated example and combine protocols (In Rust you can do both)
guidorice
guidorice15mo ago
I found a better link for the WWDC 2015 talks (the protocol oriented programming, and the related value types talk) https://archive.org/details/wwdc2015videos/ 🥳
Want results from more Discord servers?
Add your server