Hi,
I have some more thoughts about the type system, but didn't want to put it all in one mail.
The way you declare similarities in the type system, makes me a little bit nervous.
If a Type has fields or properties in common, you define an abstract type and make everything inherit from it.
This is nice, but the compiler/programmer can’t check without additional work, if the actual type really has the correct fields or properties.
If you do something like Type injection, things would be a lot more concise.
Example:
abstract WithShape
type Shape <: WithShape
boundingBox
end
type Polygon <: WithShape
@inject Shape
points::Array{Vector, 1}
end
type Circle <: WithShape
@inject Shape
r::Int
middle::Vector
end
function drawBackground(x::WithShape)
….
end
The macro inject easy to implement(if you want I can post the code), but the declaration of the abstract WithShape
and the <: WithShape
should be generated automatically.
Also, this is the point where multiple inheritance becomes very meaningful, as you might want to inject more than one type (I understood from the mailinglist, that this is in development, but hard to implement).
I’m not sure if I understand you right in the Docs for the Type system, but it seems that the functionality I describe is not wanted for a good reason.
Well, I think this could be some way of having an inheritance like functionality.
I think, that the function drawbackground
becomes a lot more transparent to the programmer, as he can look up the type WithShape
and find out the fields it has.
Without this, one would have to go through all subtypes of WithShape
to see what they have in common.
Also someone who just inherits from WithShape
, without paying attention, could break the function drawBackground.
All in all, the function drawBackground
couldn’t guarantee, that it can work with all subtypes of WithShape
, which makes it harder to see, what the function actually does.
This, plus injections at runtime would bring Julia closer to Scala in a (good?) way!
Is there any chance, that this will be implemented?
Or am I missing good reasons, why this is unwanted behavior?
Kind regards,
Simon
Okay I guess this has been sufficiently discussed.
Just one last question:
What do you think about this “design pattern”:function render(a::WithOpenGLBuffer) ...render buffer end function render(a::Shape) buffer = createOpenGLBufferFromShape(a) @inject a <-- Buffer render(a) end function modify(a::Shape) @remove a OpenGLBuffer ...do modifications end
I’m very tempted to use this.
I think this a general pattern for the case, where you need to calculate some kind of representation, that gets invalidated if you do any modification.
With the representation it gets treated differently, as you can do something ( like displaying) directly without any precalculations.Alternatively one would need to carry around an additional field, that doesn’t really has to do with the type itself, which then needs to be checked for initialization ( which doesn’t even work when you have immutable types)
I don’t really trust my judgement here, so what do you think?
Is this a good use case for injections?