std.experimental.allocator and @nogc

rikki cattermole via Digitalmars-d digitalmars-d at puremagic.com
Mon May 9 07:19:51 PDT 2016


On 10/05/2016 1:05 AM, ZombineDev wrote:
> 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;
> }

Regarding information not being available, its definitely available.
E.g. for Windows you have to use DirectX to grab luminosity but that 
will be guaranteed to be available so that isn't a worry.

And sure a window can change the monitor (primary) it is on, but that 
isn't what you're asking for now is it? You're asking for the current 
status as of the function call.

> 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);

Ewww changing of state.
No really, I do not like that.
Also __handle is very error prone, the reason why it has the underscores 
is so there is a way to give commonly the system handle while also 
recommending against (since you need to know what the underlying 
implementation is).

Also please note that I am doing the image library very differently. 
There templates do rule. Just not here :)

Since you want to play around with this area have fun with making it 
work with UTF encoding and in general the event loop. It is a heck a lot 
of work.
Bonus points if you get screenshots working.


More information about the Digitalmars-d mailing list