November 12, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Monday, 11 November 2013 at 04:18:09 UTC, Walter Bright wrote:
> The compiler would benefit from knowing which modules are from a shared library, and it needs to anyway in order to distinguish between dllimport and dllexport.
>
We didn't found any reasonably simple solution to pass this information to the compiler. You'd have to explicitly list ALL modules that are supposed to be linked into the same DLL when compiling an object file.
|
November 12, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Monday, 11 November 2013 at 18:21:21 UTC, Walter Bright wrote:
> I do understand that. I just have strong doubts about whether that is the best approach or not.
>
We made a slight adjustment on how exported data symbols should be accessed, always through a pointer indirection. Calling exported function already works transparently and accessing exported TLS variables isn't the most urgent issue.
Given that exported data variables should be rare we're trading a tiny implementation change for a no worries export attribute.
|
November 12, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On 11/12/2013 06:46 AM, Andrei Alexandrescu wrote:
> On 11/11/13 2:36 PM, Timon Gehr wrote:
>> On 11/11/2013 11:02 PM, deadalnix wrote:
>>> On Sunday, 10 November 2013 at 12:39:35 UTC, Timon Gehr wrote:
>>>> What about Object.factory?
>>>
>>> I always though of it as a misfeature.
>>
>> Me too.
>
> ... well time to substantiate.
>
> Andrei
- Every class in any imported module will need to show up in the generated code even if it is never used unless global static analysis is carried out on arguments to Object.factory.
- If I know the fully qualified name of a class, there are better ways to instantiate this class than passing a string containing that name to Object.factory in order to call the default constructor.
- The functionality provided by Object.factory is trivially replaced by a solution more specifically tailored to the problem at hand using compile-time reflection.
|
November 12, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 11/12/13 2:36 PM, Timon Gehr wrote: > On 11/12/2013 06:46 AM, Andrei Alexandrescu wrote: >> On 11/11/13 2:36 PM, Timon Gehr wrote: >>> On 11/11/2013 11:02 PM, deadalnix wrote: >>>> On Sunday, 10 November 2013 at 12:39:35 UTC, Timon Gehr wrote: >>>>> What about Object.factory? >>>> >>>> I always though of it as a misfeature. >>> >>> Me too. >> >> ... well time to substantiate. >> >> Andrei > > - Every class in any imported module will need to show up in the > generated code even if it is never used unless global static analysis is > carried out on arguments to Object.factory. Correct. On the other hand, a lot of unused classes in used modules seems to indicate a problem with the system's design. > - If I know the fully qualified name of a class, there are better ways > to instantiate this class than passing a string containing that name to > Object.factory in order to call the default constructor. What are the better ways? Note that most of the time you don't "know" the name of a class - you get it down the wire during some deserialization. So there must be some way to build an object from a token representation of the object. > - The functionality provided by Object.factory is trivially replaced by > a solution more specifically tailored to the problem at hand using > compile-time reflection. It's not quite trivial - somewhere there has to be a map and registration and lookup and whatnot. I don't see it why it's unbecoming for such functionality to be part of the standard library. I would agree, however, that it's a judgment call whether it should be wired in or provided on demand. Andrei |
November 12, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On Tuesday, 12 November 2013 at 22:36:22 UTC, Timon Gehr wrote: > - Every class in any imported module will need to show up in the generated code even if it is never used unless global static analysis is carried out on arguments to Object.factory. > > - If I know the fully qualified name of a class, there are better ways to instantiate this class than passing a string containing that name to Object.factory in order to call the default constructor. > > - The functionality provided by Object.factory is trivially replaced by a solution more specifically tailored to the problem at hand using compile-time reflection. + 1. To test, I made a Factory template that works like this: --- unittest { import std.traits : fullyQualifiedName; interface I {} class A : I {} class B : I {} alias f = Factory!(I, A, B); static assert(is(f.Product == I)); I a = f.create(fullyQualifiedName!A); assert(cast(A)a); I b = f.create(fullyQualifiedName!B); assert(cast(B)b); } --- Some notes: * The first parameter, the Product parameter, which can be any class or interface, is required because CommonType is always Object when given a heterogeneous list of classes. I assume this is because of the difficulty of choosing a common interface when multiple interfaces are present. * All subsequent parameters, the factory provider classes, are of course checked that they actually implement the Product, whether as a base class or an interface. Is a bit of a gotcha because AliasThis has to be "worked around" in the checking code. * Implementation uses a sorted array instead of an AA because AAs can't be transferred from CT to RT yet. * The array is immutable, so the same list is used for the same Factory across threads (but I suppose that has no real significance, just an observation). * If the Product member is deemed unnecessary, it could just be a function template instead of a template with two members (Product and create). Advantages over Object.factory: * The opCall returns Product, not Object, so client code doesn't need to cast in most circumstances. * `fullyQualifiedName` is used in the example because it internally uses `TypeInfo_Class.create`, which requires the full, internal names of the A and B types, which of course, are nested in a unittest. However, since the range of implementations are known, it could be amended to statically figure out a less strict naming scheme. In this case, just "A" and "B" could be made valid without ambiguity. Object.factory cannot practically do this. * Interestingly, since it knows all the constructors, it could present an overload set of the constructors that all implementors support, with some implementation effort! * Lookup has the opportunity to be a lot faster than Object.factory due to the smaller set of providers. * The runtime list of providers does not contain types that aren't part of the set (duh), hence no bloat. The disadvantage is that all implementing types must be passed at compile-time. That is the only advantage of Object.factory, AFAICS. As it seems like a very niche need that everyone has to pay for, I don't think Object.factory carries its weight. |
November 12, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jakob Ovrum | On 11/12/13 3:05 PM, Jakob Ovrum wrote:
> On Tuesday, 12 November 2013 at 22:36:22 UTC, Timon Gehr wrote:
>> - Every class in any imported module will need to show up in the
>> generated code even if it is never used unless global static analysis
>> is carried out on arguments to Object.factory.
>>
>> - If I know the fully qualified name of a class, there are better ways
>> to instantiate this class than passing a string containing that name
>> to Object.factory in order to call the default constructor.
>>
>> - The functionality provided by Object.factory is trivially replaced
>> by a solution more specifically tailored to the problem at hand using
>> compile-time reflection.
>
> + 1.
>
> To test, I made a Factory template that works like this:
>
> ---
> unittest
> {
> import std.traits : fullyQualifiedName;
>
> interface I {}
> class A : I {}
> class B : I {}
>
> alias f = Factory!(I, A, B);
Stopped reading here, and everybody should. There is a thorough treatment of object factories in "Modern C++ Design" which I recommend not because I wrote it, but because it's thorough. Part of it is to show why the approach above is marred by dependency issues and should often be avoided.
Andrei
|
November 13, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Tuesday, 12 November 2013 at 23:47:10 UTC, Andrei Alexandrescu wrote:
> On 11/12/13 3:05 PM, Jakob Ovrum wrote:
>> On Tuesday, 12 November 2013 at 22:36:22 UTC, Timon Gehr wrote:
>>> - Every class in any imported module will need to show up in the
>>> generated code even if it is never used unless global static analysis
>>> is carried out on arguments to Object.factory.
>>>
>>> - If I know the fully qualified name of a class, there are better ways
>>> to instantiate this class than passing a string containing that name
>>> to Object.factory in order to call the default constructor.
>>>
>>> - The functionality provided by Object.factory is trivially replaced
>>> by a solution more specifically tailored to the problem at hand using
>>> compile-time reflection.
>>
>> + 1.
>>
>> To test, I made a Factory template that works like this:
>>
>> ---
>> unittest
>> {
>> import std.traits : fullyQualifiedName;
>>
>> interface I {}
>> class A : I {}
>> class B : I {}
>>
>> alias f = Factory!(I, A, B);
>
> Stopped reading here, and everybody should. There is a thorough treatment of object factories in "Modern C++ Design" which I recommend not because I wrote it, but because it's thorough. Part of it is to show why the approach above is marred by dependency issues and should often be avoided.
Sure, it has dependency issues, it needs to know all the types then and there, with is the anti-thesis of many factories. So, call it something else, like TypeMap, and it's still a useful type.
But alright, it is not a good factory.
|
November 13, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jakob Ovrum | On Wednesday, 13 November 2013 at 00:03:49 UTC, Jakob Ovrum wrote:
> But alright, it is not a good factory.
Well, D compile-time reflection allows to define factory that finds all classes that implement given interface and provides them for construction, with no explicit list.
I have used this in D1 though because of limited compile-time reflection capabilities there.
|
November 13, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On 11/12/13 4:18 PM, Dicebot wrote:
> On Wednesday, 13 November 2013 at 00:03:49 UTC, Jakob Ovrum wrote:
>> But alright, it is not a good factory.
>
> Well, D compile-time reflection allows to define factory that finds all
> classes that implement given interface and provides them for
> construction, with no explicit list.
I don't think all classes in a system are discoverable during compilation. This is the part of Object.factory that is not easy to replace. There must be a global map somewhere and a per-module registration during initialization.
Andrei
|
November 13, 2013 Re: DIP 45 - approval discussion | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Wednesday, 13 November 2013 at 00:25:36 UTC, Andrei Alexandrescu wrote:
> I don't think all classes in a system are discoverable during compilation. This is the part of Object.factory that is not easy to replace. There must be a global map somewhere and a per-module registration during initialization.
>
> Andrei
Sure, this topic was already discussed in __traits(getUnittest) context recently, similar problem. You can find all classes that transitively accessible from context via imports - this is a natural limitation of compile-time reflection. Sometimes it is enough, sometimes registration is necessary. But it is a nice tool to have.
|
Copyright © 1999-2021 by the D Language Foundation