www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - std.experimental.allocator and nogc

reply Danni Coy via Digitalmars-d <digitalmars-d puremagic.com> writes:
It seems to me, that std.experimental.allocator should work with  nogc
annotated functions if none of the allocators being used are the
gcallocator, though it's not at all clear to me how this would work.

Are there plans for this?
May 08 2016
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 09/05/2016 4:50 PM, Danni Coy via Digitalmars-d wrote:
 It seems to me, that std.experimental.allocator should work with  nogc
 annotated functions if none of the allocators being used are the
 gcallocator, though it's not at all clear to me how this would work.

 Are there plans for this?
If only we had assumenogc ala safe's trusted but for nogc we could definitely do it then.
May 08 2016
parent reply Hildigard Sandyman <HildigardSandyman inbound.plus> writes:
On Monday, 9 May 2016 at 05:00:31 UTC, rikki cattermole wrote:
 On 09/05/2016 4:50 PM, Danni Coy via Digitalmars-d wrote:
 It seems to me, that std.experimental.allocator should work 
 with  nogc
 annotated functions if none of the allocators being used are 
 the
 gcallocator, though it's not at all clear to me how this would 
 work.

 Are there plans for this?
If only we had assumenogc ala safe's trusted but for nogc we could definitely do it then.
I think you've been misleaded by the initial Q that spuriously assumes that allocators are not nogc but nogc allocators seems to be a milestone that's in our back now.
May 08 2016
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 09/05/2016 5:16 PM, Hildigard Sandyman wrote:
 On Monday, 9 May 2016 at 05:00:31 UTC, rikki cattermole wrote:
 On 09/05/2016 4:50 PM, Danni Coy via Digitalmars-d wrote:
 It seems to me, that std.experimental.allocator should work with  nogc
 annotated functions if none of the allocators being used are the
 gcallocator, though it's not at all clear to me how this would work.

 Are there plans for this?
If only we had assumenogc ala safe's trusted but for nogc we could definitely do it then.
I think you've been misleaded by the initial Q that spuriously assumes that allocators are not nogc but nogc allocators seems to be a milestone that's in our back now.
All I know is that until IAllocator can be nogc, we can't use theAllocator + processAllocator. Which kinda requires assumenogc for the GC allocator.
May 08 2016
parent reply Hildigard Sandyman <HildigardSandyman inbound.plus> writes:
On Monday, 9 May 2016 at 05:27:24 UTC, rikki cattermole wrote:
 On 09/05/2016 5:16 PM, Hildigard Sandyman wrote:
 On Monday, 9 May 2016 at 05:00:31 UTC, rikki cattermole wrote:
 On 09/05/2016 4:50 PM, Danni Coy via Digitalmars-d wrote:
 It seems to me, that std.experimental.allocator should work 
 with  nogc
 annotated functions if none of the allocators being used are 
 the
 gcallocator, though it's not at all clear to me how this 
 would work.

 Are there plans for this?
If only we had assumenogc ala safe's trusted but for nogc we could definitely do it then.
I think you've been misleaded by the initial Q that spuriously assumes that allocators are not nogc but nogc allocators seems to be a milestone that's in our back now.
All I know is that until IAllocator can be nogc, we can't use theAllocator + processAllocator. Which kinda requires assumenogc for the GC allocator.
It's true but... why do you bother with IAllocator ? Everything can be set a compile time with a template parameter. As long as the param is a struct with allocate/deallocate/reallocate it's OK. you can use already a good part of the package content in a nogc fashion. Do you have an example where IAllocator must be used and where, for example, Mallocator can't be passed ?!
May 08 2016
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 09/05/2016 6:22 PM, Hildigard Sandyman wrote:
 It's true but... why do you bother with IAllocator ? Everything can be
 set a compile time with a template parameter. As long as the param is a
 struct with allocate/deallocate/reallocate it's OK. you can use already
 a good part of the package content in a  nogc fashion.

 Do you have an example where IAllocator must be used and where, for
 example, Mallocator can't be passed ?!
The moment where you need to use OOP, you most definitely need IAllocator. I cannot make a windowing library without the use of IAllocator. You can't always template functions with the type that is the allocator. Its just not possible or reasonable.
May 08 2016
next sibling parent Hildigard Sandyman <HildigardSandyman inbound.plus> writes:
On Monday, 9 May 2016 at 06:35:36 UTC, rikki cattermole wrote:
 On 09/05/2016 6:22 PM, Hildigard Sandyman wrote:
 It's true but... why do you bother with IAllocator ? 
 Everything can be
 set a compile time with a template parameter. As long as the 
 param is a
 struct with allocate/deallocate/reallocate it's OK. you can 
 use already
 a good part of the package content in a  nogc fashion.

 Do you have an example where IAllocator must be used and 
 where, for
 example, Mallocator can't be passed ?!
The moment where you need to use OOP, you most definitely need IAllocator. I cannot make a windowing library without the use of IAllocator. You can't always template functions with the type that is the allocator. Its just not possible or reasonable.
Yes there's a problem with this but that doesn't mean that whole package is concerned. The first message clearly orientates the answer:
 It seems to me, that std.experimental.allocator should work 
 with  nogc
It should == It doesn't yet
 Are there plans for this ?
Question is based on the previous wrong assumption, but since the most important part of the message is the Q itself, it makes people swallow the craps. So basically anyone not well informed who reads this can deduce that it doesn't work at all.
May 09 2016
prev sibling parent reply ZombineDev <petar.p.kirov gmail.com> writes:
On Monday, 9 May 2016 at 06:35:36 UTC, rikki cattermole wrote:
 On 09/05/2016 6:22 PM, Hildigard Sandyman wrote:
 It's true but... why do you bother with IAllocator ? 
 Everything can be
 set a compile time with a template parameter. As long as the 
 param is a
 struct with allocate/deallocate/reallocate it's OK. you can 
 use already
 a good part of the package content in a  nogc fashion.

 Do you have an example where IAllocator must be used and 
 where, for
 example, Mallocator can't be passed ?!
The moment where you need to use OOP, you most definitely need IAllocator. I cannot make a windowing library without the use of IAllocator. You can't always template functions with the type that is the allocator. Its just not possible or reasonable.
You don't need OOP for neither windowing, nor image abstraction. None of the OS APIs require it. I haven't considered using classes for my projects for more than a year, because D offers much better ways to solve most problems and cuz programming in a Java-like way just sucks. Functions that require memory allocation should take alias allocator template parameters. And everything should be templated for maximum flexibility! For example, instead writing Image interfaces/classes or even structs, just offer a couple of free functions that convert from .bmp/.png/.jpg/ etc. to ndslice and back. For example: /** * Automatically determines the image format and reads the * image in memory by converting each pixel to `ColorType`. * Internally calls readImage!(ImageFormat.png) / * readImage!(ImageFormat.bmp / etc. depending on * the deduced image format. * * If the underlying `allocator` is `MmapAllocator`, it maps * the file into memory, instead of copying it. * * Parameters: * file_path = string input range specifying location * of the image to be read * * Returns: * `Slice!(N, RandAccessR!ColorType)` where `N` is >= 2. * (All images are conceptually two dimensional, but may * be internally divided into blocks). */ auto readImage(ColorType, alias allocator = GCAllocator.instance, R)(R file_path) if (isStringRange!R && isColor!ColorType && is(typeof(allocatorInstance!allocator))); // example 1 - image manipulation unittest { auto tinyAlloc = StackAllocator!256(); auto imgAlloc = ScopedAllocator!MmapAllocator; alias C = Color!(ColorFormat.RGBA8); auto images = ["./img1.jpg", "../images/img2.png", "./mask.bmp"] .map!(path => path.readImage!(C, imgAlloc)) .array!tinyAlloc; // force eager evaluation auto result = makeSlice!C(imgAlloc, image[0].shape); auto xyzo_slice = lockstep(aliasSeqOf!images, result); xyzo_slice.each!((in ref x, in ref y, in ref y, ref o) => o = (x + y) * z)(); result.writeImage!(ImageFormat.png)("./output.png"); // All allocated memory is freed at the end of the scope. } // example 2 - image viewer void main(string[] args) { enforce(args.length == 2, "Usage: imgshow <image-path>"); enforce(exists(args[1], "%s doesn't exist".format(args[1])); auto imgAllocator = ScopedAllocator!MmapAllocator; auto uiAllocator = ScopedAllocator!Mallocator; alias C = Color!(ColorFormat.RGBA8); auto img = readImage!(C, imgAllocator)(args[1]); // I don't think you need heap allocations for basic stuff // with Win32 but still I'm not familiar with every API out there. // `window` is RAII struct that should manage GUI resources // as needed. auto window = createWindowWithImage!uiAllocator(img); bool running = true; window.show.enterEventLoop!( (QuitEvent q) { running = false; }, (ResizeEvent r) => false /* do not allow resizing */ (MouseClick m) /* color picker */ { writefln("pixel at [%s, %s] is %s", m.coords.expand, img[m.coords]); } /* ignore other events */ )(&running); } See, no classes or interfaces were harmed during the making of those examples :D
May 09 2016
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
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.
May 09 2016
parent reply ZombineDev <petar.p.kirov gmail.com> writes:
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?
May 09 2016
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
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.
May 09 2016
parent reply ZombineDev <petar.p.kirov gmail.com> writes:
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: // 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); } 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); 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.
May 09 2016
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
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?
 // 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?
 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.
 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.
May 09 2016
parent reply ZombineDev <petar.p.kirov gmail.com> writes:
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.
May 09 2016
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
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. PR's welcome. https://github.com/rikkimax/alphaPhobos/ FYI, I'll be streaming in a minute https://www.livecoding.tv/alphaglosined/
May 09 2016
parent reply ZombineDev <petar.p.kirov gmail.com> writes:
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.
May 09 2016
parent rikki cattermole <rikki cattermole.co.nz> writes:
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.
May 09 2016
prev sibling parent Danni Coy via Digitalmars-d <digitalmars-d puremagic.com> writes:
 It's true but... why do you bother with IAllocator ? Everything can be set a
 compile time with a template parameter. As long as the param is a struct
 with allocate/deallocate/reallocate it's OK. you can use already a good part
 of the package content in a  nogc fashion.

 Do you have an example where IAllocator must be used and where, for example,
 Mallocator can't be passed ?!
How is that going to work in a situation where the code is in a library that you are linking to rather than compiling?
May 09 2016
prev sibling parent reply Hildigard Sandyman <HildigardSandyman inbound.plus> writes:
On Monday, 9 May 2016 at 04:50:59 UTC, Danni Coy wrote:
 It seems to me, that std.experimental.allocator should work 
 with  nogc annotated functions if none of the allocators being 
 used are the gcallocator, though it's not at all clear to me 
 how this would work.

 Are there plans for this?
It already mostly works in nogc block: - Mallocator and AlignedMallocator are nogc. - make() dispose(), shrinkArray(), etc are templatized function so they infer nogc. - higher level blocks also infer nogc. example: ---- import std.experimental.allocator; import std.experimental.allocator.mallocator; import std.experimental.allocator.building_blocks.free_list; struct Foo{} void main(string[] args) nogc { Foo* foo = Mallocator.instance.make!Foo; Mallocator.instance.dispose(foo); uint[] arr; arr = Mallocator.instance.makeArray!uint(8); Mallocator.instance.shrinkArray(arr,1); Mallocator.instance.dispose(arr); FreeList!(Mallocator,0,size_t.sizeof) fl; auto p = fl.allocate(8); fl.deallocate(p); } ---- Initially it was not the case but it's been done latest months, e.g in this PR: https://github.com/dlang/phobos/pull/3856
May 08 2016
parent Danni Coy via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Mon, May 9, 2016 at 3:10 PM, Hildigard Sandyman via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Monday, 9 May 2016 at 04:50:59 UTC, Danni Coy wrote:
 It already mostly works in  nogc block:
 - Mallocator and AlignedMallocator are  nogc.
I was trying to use BitmappedBlock, AllocatorList and MmapAllocator with nogc without much luck. BitmappedBlock and AllocatorList, both take allocators as arguments so they may or may not use GC depending on which allocators they are using. I was wondering how D would handle this.
May 09 2016