Consider the following code:
abstract type AbstractTransport end
mutable struct Car <: AbstractTransport
function Car(name::String, engine_type::String, number_of_people::Int32)
# Validation left out.
mutable struct StarShip <: AbstractTransport
# Validation left out.
As you can see both transports are sub types of
AbstractTransport but they don’t have consistent fields. I won’t get an error until I use a method that requires certain fields:
uss_enterprise = StarShip(100)
transport_info(uss_enterprise) # type StarShip has no field name
Is there a way to make certain fields mandatory during construction of sub types? For example in OOP, you would have an
Abstract class that contains all the attributes common to all subclasses. When constructing an object, you would pass the required fields to the
Abstract class using the constructor.
In OOP, I would put the
engine_type in the abstract class, so even if a subclass doesn’t provide new attributes it at least has to provide
I could use
hasfields() but then each method that uses an
AbstractTransport would need to check for the required fields.
Julia has no data inheritance. IMHO, the Julian way is to either:
- Do not ever access fields of an object that you received from a parameter typed generically. Create two functions
engine_type, and document they should be defined for every subtype of this
abstract type, use these functions instead. In other, basically, use setters and getters you want to use OOP concepts.
- Document the
abstract type to indicate any subtype needs to have a field called
engine_type. I think this is clunky and has basically no performance improvements over getters and setters, but hey, it is a solution.
- Combine both previous solutions with a small dose of enforcement. When you define the getters and setters, let the generic version (that does not define the type of any arguments) check if the field exists, if it exists use the field, otherwise throw an error explaining to the used that “Type X is a subtype of Type Y and breached the contract by not having a field called
z.”. For the best you should yet use the getters and setters in your generic code but at least people that subtype your type “in the wrong fashion” will get a good error message and they do not need to define their own getters and setters (the generic one will do the job for them).
Probably there some hacky improvements to these ideas, but I would recommend following either path 1 or 3. A solution in a kind different direction would be creating a
TransportInfo concrete type, with both
engine_type fields, and require (by means of documentation) that your
AbstractTransport subtypes define a method for
get_transport_info (or some better name) that always return a