March 17, 2014
On 3/17/2014 1:35 AM, Iain Buclaw wrote:
> Right,

If so, why do all modules need the version statement?
March 17, 2014
On 17 March 2014 08:55, Walter Bright <newshound2@digitalmars.com> wrote:
> On 3/17/2014 1:35 AM, Iain Buclaw wrote:
>>
>> Right,
>
>
> If so, why do all modules need the version statement?

That is a question to ask the historical maintainers of cairoD. Having a look at it now.  It has a single config.d with enum bools to turn on/off features.
March 17, 2014
On 3/17/2014 12:53 AM, Iain Buclaw wrote:
> If it's in any relation to your comments in the PR, my opinion is that they are
> irrelevant to to PR in question, but they *are* relevant in their own right and
> warrant a new bug/PR to be raised.


Here it is:

https://github.com/D-Programming-Language/druntime/pull/741

I think it shows it is very relevant to your PR, as in fact I included your files essentially verbatim, I just changed the package layout.
March 17, 2014
On 3/17/2014 2:32 AM, Iain Buclaw wrote:
> On 17 March 2014 08:55, Walter Bright <newshound2@digitalmars.com> wrote:
>> On 3/17/2014 1:35 AM, Iain Buclaw wrote:
>>>
>>> Right,
>>
>>
>> If so, why do all modules need the version statement?
>
> That is a question to ask the historical maintainers of cairoD.
> Having a look at it now.
> It has a single config.d with enum bools to
> turn on/off features.

If those enums are controlled by a version statement, then the version will have to be set for every source file that imports it. This is not the best design - the abstractions are way too leaky.
March 17, 2014
On 2014-03-17 01:20:37 +0000, Walter Bright <newshound2@digitalmars.com> said:

> On 3/15/2014 6:44 AM, Johannes Pfau wrote:
>> Then in cairo.d
>> version(CAIRO_HAS_PNG_SUPPORT)
>> {
>>     extern(C) int cairo_save_png(char* x);
>>     void savePNG(string x){cairo_save_png(toStringz(x))};
>> }
> 
> try adding:
> 
>    else
>    {
>         void savePNG(string x) { }
>    }
> 
> and then your users can just call savePNG without checking the version.

Adding a stub that does nothing, not even a runtime error, isn't a very good solution in my book. If this function call should fail, it should fail early and noisily.

So here's my suggestion: use a template function for the wrapper.

	extern(C) int cairo_save_png(char* x);
	void savePNG()(string x){cairo_save_png(toStringz(x));}

If you call it somewhere it and cairo_save_png was not compiled in Cairo, you'll get a link-time error (undefined symbol cairo_save_png). If you don't call savePNG anyhere there's no issue because savePNG was never instantiated.

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca

March 17, 2014
On Monday, 17 March 2014 at 06:26:09 UTC, Marco Leise wrote:
> About two years ago we had that discussion and my opinion
> remains that there are too many "if"s and "assume"s for the
> compiler.
> It is not so simple to trace back where an object originated
> from when you call a method on it.

It might not be easy, but in my view the language should be designed to support future advanced compilers. If D gains traction on the C++ level then the resources will become available iff the language has the right constructs or affords extensions that makes advanced optimizations tractable. What is possible today is less imoortant...

 >It could be created though
> the factory mechanism in Object using a runtime string or it

If it is random then you know that it is random. If you want speed you create separate paths for the dominant instance types. Whole program optimizations is guided by profiling data.


> There are plenty of situations where it is virtually
> impossible to know the instance type statically.

But you might know that it is either A and B or C and D in most cases. Then you inline those cases and create specialized execution paths where profitable.

> Whole program analysis only works on ... well, whole programs.
> If you split off a library or two it doesn't work. E.g. you
> have your math stuff in a library and in your main program
> you write:
>
>   Matrix m1, m2;
>   m1.crossProduct(m2);
>
> Inside crossProduct (which is in the math lib), the compiler
> could not statically verify if it is the Matrix class or a
> sub-class.

In my view you should avoid not having source access, but even then it is sufficient to know the effect of the function. E.g. you can have a high level specification language asserting pre and post conditions if you insist on closed source.

>> With a compiler switch or pragmas that tell the compiler what can be dynamically subclassed the compiler can assume all leaves in the compile time specialization hierarchies to be final.
>
> Can you explain, how this would work and where it is used?

You specify what plugins are allowed to do and access at whatever resolution is necessary to enable the optimizations your program needs?

Ola.
March 17, 2014
Am Mon, 17 Mar 2014 08:35:45 +0000
schrieb Iain Buclaw <ibuclaw@gdcproject.org>:

> > If you need to -fversion=CAIRO_HAS_PNG_SUPPORT for every file that imports it, you have completely misunderstood the design I suggested.
> >
> > 1. Encapsulate the feature in a function.
> >
> > 2. Implement the function in module X. Module X is the ONLY module that needs the version. In module X, define the function to do nothing if version is false.
> >
> > 3. Nobody who imports X has to define the version.
> >
> > 4. Just call the function as if the feature always exists.
> >

Clever, but potentially dangerous once cross-module inlining starts working (The inlined code could be different from the code in the library).
March 17, 2014
Am Mon, 17 Mar 2014 03:49:24 -0700
schrieb Walter Bright <newshound2@digitalmars.com>:

> On 3/17/2014 2:32 AM, Iain Buclaw wrote:
> > On 17 March 2014 08:55, Walter Bright <newshound2@digitalmars.com> wrote:
> >> On 3/17/2014 1:35 AM, Iain Buclaw wrote:
> >>>
> >>> Right,
> >>
> >>
> >> If so, why do all modules need the version statement?
> >
> > That is a question to ask the historical maintainers of cairoD.
> > Having a look at it now.
> > It has a single config.d with enum bools to
> > turn on/off features.
> 
> If those enums are controlled by a version statement, then the version will have to be set for every source file that imports it. This is not the best design - the abstractions are way too leaky.

It's meant to be set at configure time, when the library
is being built, by a configure script or similar. They're not controlled
by version statements at all.

That's nothing special, it's config.h for D.


The reason all modules needed the version statement was that I didn't use the stub-function trick. Cairo also has classes which can be available or unavailable. Stubbing all these classes doesn't seem to be a good solution. I also think it's bad API design if a user can call a stub 'savePNG' function which just does nothing.

A perfect solution for cairoD needs to handle all these cases:
cairo has PNG support:             true                    false
user wants to use PNG:   optional, true, false    optional, true, false
                         ok         ok    ok       ok       error  ok


with config.d and static if:
-----------------------
enum bool CAIRO_HAS_PNG_SUPPORT = true; //true/false is inserted by
                                        //configure script
static if(CAIRO_HAS_PNG_SUPPORT)
    void savePNG();
-----------------------


library users can do this:
-----------------------
import cairo.config;
static if(!CAIRO_HAS_PNG_SUPPORT)
   assert(false, "Need PNG support");

static if(CAIRO_HAS_PNG_SUPPORT)
   //Offer option to optionally save file as PNG as well
-----------------------

if they don't check for CAIRO_HAS_PNG_SUPPORT and just use
savePNG then
(1) it'll work if PNG support is available
(2) the function is not defined if png support is not available

With versions the user has no way to know if the library actually supports PNG or not. He can only guess and the optional case can't be implemented at all.
March 17, 2014

On 17.03.2014 04:45, Marco Leise wrote:
> Am Sun, 16 Mar 2014 12:28:24 +0100
> schrieb Rainer Schuetze <r.sagitario@gmx.de>:
>
> Are we still in the same discussion?

I guess we are drifting off. I was just considering some alternatives to "final(false)" which doesn't work.

> The only thing I miss is that among the several ways to
> express function signatures in D, some don't allow you to
> specify all attributes. My memory is blurry, but I think it
> was function literals that I used to write stubs for runtime
> loaded library functionality.
>
>> […] though I would prefer avoiding string mixins, maybe by providing a
>> function type as prototype:
>>
>> alias export extern(Windows) void function() fnWINAPI;
>>
>> @functionAttributesOf!fnWINAPI HANDLE GetCurrentProcess();
>
> That is too pragmatic for my taste. Something that you define
> in code should be usable as is. It is like taking the picture
> of a red corner sofa just to describe the color to someone.
>
> In that specific case, why does this not work for you?:
>
> nothrow extern(Windows) {
>    HANDLE GetCurrentProcess();
> }
>

The attributes sometimes need to be selected conditionally, e.g. when building a library for static or dynamic linkage (at least on windows where not everything is exported by default). Right now, you don't have an alternative to code duplication or heavy use of string mixins.
March 17, 2014
On Sunday, 16 March 2014 at 08:04:24 UTC, Iain Buclaw wrote:
>
> Indeed other stuff needs to be done, it just so happens that  thanks to
> sys.posix's bad design splitting out other modules into ports  will be more
> a pain.  But it shows how *no one* in that thread who responded
>  either
> against the first pull, or went off and hijacked the second had
>  a Scooby
> about the issue being addressed.  Didn't even have the curiosity to give
> alternate suggestions.

Pretty sure I agreed with your motivation here, though I figured
I'd defer the design to someone who has experience actually
dealing with this many ports.