std.experimental.allocator and @nogc

ZombineDev via Digitalmars-d digitalmars-d at puremagic.com
Mon May 9 06:05:39 PDT 2016


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.


More information about the Digitalmars-d mailing list