On Monday, 9 May 2016 at 12:37:24 UTC, rikki cattermole wrote:
On 10/05/2016 12:33 AM, ZombineDev wrote:
On Monday, 9 May 2016 at 12:02:19 UTC, rikki cattermole wrote:
On 09/05/2016 11:56 PM, ZombineDev wrote:
On Monday, 9 May 2016 at 11:20:00 UTC, rikki cattermole
wrote:
On 09/05/2016 11:12 PM, ZombineDev wrote:
On Monday, 9 May 2016 at 10:33:27 UTC, rikki cattermole
wrote:
I've done windowing and image libraries before.
You are correct, you do not need OOP.
But if you want to keep implementation nicely separated
out from
usage, you really do. Which is a major part of my
requirements.
Well, in my example above, everything is nicely separated,
easy to
use,
yet quite flexible. And still there is no Java-style OOP.
Do you have
any examples, where the use of classic OOP would provide a
strictly
superior design?
You're using templates. While this might be ok for image
library.
I cannot use this for the windowing library. The
implementation may
not be known and must be plugable at runtime.
The reality is, just because you say you know about
something at
compile time doesn't mean the system that runs a program
does.
I'm still not convinced. You have a fixed at CT number of
implementations. Even if you don't know at CT the actual
platform that
will be used, you can still choose at RT the correct
template. Example:
You do not.
Shared libraries remember them?
You will statically link the windowing library and it will
dynamically
load the necessary shared/dynamic libaries of the platform at
runtime.
What's the problem? E.g. Derelict* does the same.
// platform name can be "X11", "mir", "Wayland", etc.
auto getPlatformWindow(CTArgs...)(string platformNameRTArg)
{
switch (platformNameRTArg.toLower)
{
default:
enforce(false, "Unknown platform: " ~
platformNameRTArg);
foreach (platform; EnumMembers!Platform)
case name.stringof:
// Use std.experiment.typecons.Wrap if you
need a
common type.
return getWindow!(name, CTArgs);
}
assert (0);
}
Platform is undefined, did you mean IPlatform?
Platform obviously an enum. The return type can be a plain
struct, a
Variant, or a std.experimental.typecons.wrap, depending on
your needs.
But that's besides the point. Even with OOP, your return
type can be an
interface that has template parameters like allocators,
policies, etc.
You're providing some the arguments at CT and the rest of
the return
type is dynamically polymorphic. E.g.:
interface Window(Allocator, Policy);
Window!(Allocator, Policy) getWindow(alias allocator,
Policy)(RunTimeArgs);
Sure you can, but now you have added another layer of
indirection
between implementation and usage because you can't use
templated types
in between.
There's no indirection (besides the interface, which would
also be the
case with your approach) and you **should** use templated
types :)
My point is that there's no need for IAllocator, even if you
want to use
OOP so badly.
But in most cases you will either write different code for
different
platforms, making interfaces unnecessary, or you would be
able to hide
the differences behind a struct.
And when the allocator and the other policies are template
parameters
you will know at CT that your code is @nogc.
Again, no templates. You cannot initialize them at runtime,
and since
you won't know all implementations until it executes, well,
you've got
a problem.
Its a many to many problem. I faced this with Cmsed as well.
As I demonstrated, it's not a problem. You just need to choose
the
template at runtime. You have a fixed number of
implementations which
are all statically linked. Only the one chosen at runtime will
be
initialized and at the moment of initialization it can do the
necessary
dynamic loading.
In the example above:
interface Window(Allocator, Policy);
Window!(Allocator, Policy) getWindow(alias allocator,
Policy)(RunTimeArgs);
Since you don't need to switch Allocator implementations at
run-time
(and if you switch them you will most certainly get silent
memory
corruption), you can leverage the fact that some stuff are
known at CT
and leave the rest to RT.
At this point, all I'm going to say is, prove me wrong.
Give me all the power I have now and do it the way you want to.
Challange accepted ;)
PR's welcome.
Well, I'll maybe write my own implementation just cuz it's fun.
May be we can contribute in the future :)
https://github.com/rikkimax/alphaPhobos/
From a cursory look, I would have written
std.experimental.ui.rendering.IDisplay like this:
struct Display
{
// I prefer Nullable because not all information
// could be available on all platforms.
// May be some things are common everywhere,
// but I don't have time to check, right now.
Nullable!string name;
Nullable!vec2!ushort size;
Nullable!uint refreshRate;
Nullable!uint luminosity;
Nullable!float gamma() { return luminosity.isNull? null :
luminosity / 10f; }
// I removed windows() because you can move
// windows from on display to another.
// IMO, it's more correct to ask the window on
// which monitor(s) it is currently displayed.
// Like MonitorFromWindow on Win32
void* __handle;
}
And if the resolution/refresh rate/etc. changes, the user would
just ask again and will get a new Display instance. The nice
thing about this is that you can also use it in the opposite
direction:
Display display;
display.refreshRate = 85;
display.size = vec2(1920, 1080);
display.__handle = monitor1;
platform.setDisplayMode(display);
FYI, I'll be streaming in a minute
https://www.livecoding.tv/alphaglosined/
Sorry, no time to watch, Vulkan awaits me ;) Maybe later if
there's a recording.