November 13, 2013
On 2013-11-13 17:29, Andrei Alexandrescu wrote:

> To drive the point home: I looked once more over the code and I think
> it's too complicated for what it does. It could be improved as follows.

No, I have worked on this library for several years. I don't see how it could be less complicated for what it does. It seems you don't understand exactly what it does.

> The key to simplification is using
>
> Object create() const;

Requires a default constructor. Not good enough.

>
> static const(TypeInfo_Class) find(in char[] classname);
>
> in the same type. The procedure would go as follows:
>
> 1. Retrieve the ClassInfo object for the class name.
>
> 2. Create a default-constructed object by calling create() against the
> object obtained at (1).

As above, requires a default constructor. Not good enough.

> 3. Cast that Object down to IDeserializable, which is an interface type
> that has methods such as deserialize(Archive).

* Requires a class to implement an interface. Not good enough.
* Requires the class to manually serialize itself. Not good enough.

A serialization library need to work with third party types you don't have any control over.

> 4. If the cast failed, throw an exception - the object was not designed
> to be deserialized.
>
> 5. Otherwise, call deserialize against that object, passing it the archive.

As above, requires the class to manually serialize itself. Not good enough.

> Voila! No need for runtime registration - all user code has to do is
> implement the appropriate interface.
>
> I hope this both clarifies my point about factory being a sensible
> feature, and helps you improve your library.

Unfortunately it doesn't help at all. You clearly missed a lot of features this library has.

To be able to automatically (de)serialize an object in D you need to know its static type. That requires registering the type. Note, this is only needed if you're serializing through a base class reference.

You'll have to do a lot better than this to convince me.

Note also that I'm not against Object.factory/create, I'm arguing for it. Serialization is one example of why it's needed.

The biggest reasons for why it's looking like it does are:

* Can (de)serialize arbitrary types, even third party types you don't have any control over

* It automatically (de)serializes the objects. No need to implement a method. You can do, if you want to customize the (de)serialization

-- 
/Jacob Carlborg
November 13, 2013
13-Nov-2013 22:46, Andrei Alexandrescu пишет:
> On 11/13/13 10:41 AM, Dmitry Olshansky wrote:
>> 13-Nov-2013 13:27, Andrei Alexandrescu пишет:
>>> On 11/13/13 12:55 AM, Jacob Carlborg wrote:
>>>> On 2013-11-13 05:07, Andrei Alexandrescu wrote:
>>>>
>>>>> Then how do you figure doing this:
>>>>>
>>>>> class Streamable { ... }
>>>>> class Foo : Streamable { ... }
>>>>> class Bar : Streamable { ... }
>>>>> string className = stream.readln();
>>>>> Streamable obj = ...;
>>>>>
>>>>> How do you create obj from className, when className could be either
>>>>> "Foo" or "Bar"? In the general case there could be any number of
>>>>> classes, in different modules.
>>>>
>>>> This requires Object.factory (or equivalent) and that all subclasses
>>>> have been registered as well.
>>>
>>> With Object.factory that's taken care of already.
>>
>> I have to chime in.
>>
>> Serialization != calling default constructor by name.
>
> Of course not. It does give you access to an object with the correct
> dynamic type, and interfaces and virtual calls take care of the rest.
>

Allow me to retort, see below.
BTW the keywords here were:
_default_ and _by name_

>> Simply on the ground of "solves problem in too narrow scope for a hefty
>> coast to the user" I'd drop it.
>
> It's good. Let's keep it.

Oh, my... We've lost him :o)

Okay. Let me iterate on some facts:

1. Serialization may or may not be intrusive. There are many cases out there to externalize serialization (see e.g. boost serialization).
2. Want speed - avoid virtuals. Requiring that serialization be always done via specific virtual call harms performance.
3. Something you seem to dodge - AA lookup by fully qualified name is not fast nor convenient for many serialization backends.
4. Not everything needs to be serialized yet it's registered (and slows down lookups).
5. Forcing a pattern - every class object must be default constructible. Btw what factory does with these not defining this() ? Sadly the reality is the other way around - many interesting objects don't have valid default states.

Another point that is not a fact but rather a speculation.
I _think_ that the idea of having user pay beforehand for something simply because it may one day need it is going against D ethos. Unlike Java or .NET we have definite trend of catering for specific needs and extreme flexibility at no extra cost.

-- 
Dmitry Olshansky
November 13, 2013
On 11/13/13 11:20 AM, Jacob Carlborg wrote:
> A serialization library need to work with third party types you don't
> have any control over.

OK that convinced me. My post remains as an explanation of my point.

Andrei

November 13, 2013
Am 13.11.2013 21:36, schrieb Andrei Alexandrescu:
> On 11/13/13 11:20 AM, Jacob Carlborg wrote:
>> A serialization library need to work with third party types you don't
>> have any control over.
>
> OK that convinced me. My post remains as an explanation of my point.
>
> Andrei
>

Would you mind moving this discussion to another thread? Everytime I see a update I think its something relevant and usually its just about object.factory.

Kind Regards
Benjamin Thaut
November 13, 2013
On Wednesday, 13 November 2013 at 08:48:09 UTC, Jacob Carlborg wrote:
> On 2013-11-13 01:36, deadalnix wrote:
>
>> The serialization is a good example. You'll have to note that if the
>> code has been able to serialize the data, it can generate at compile
>> time the necessary scafolding to deserialize it.
>
> No, not necessarily. If you serialize an object through a base class reference you currently need to register that with the serializer. The static type information is lost and D doesn't provide enough runtime reflection to get the values of instance variables of an object at runtime.

OK, I see your problem here.

It is a much more general problem than the one solved by the factory. For instance, I wanted in the past to write some unittest that ensure Liskov's substitution principle (so run the unittest on subclasses).

This is fundamentally the same issue : you want to write some code that is aware of subclasses. That require somehow to be able to mixin something automatically in all subclasses.

Object.factory only solve poorly one instance of this problem.
November 14, 2013
On 2013-11-13 23:25, deadalnix wrote:

> OK, I see your problem here.
>
> It is a much more general problem than the one solved by the factory.
> For instance, I wanted in the past to write some unittest that ensure
> Liskov's substitution principle (so run the unittest on subclasses).
>
> This is fundamentally the same issue : you want to write some code that
> is aware of subclasses. That require somehow to be able to mixin
> something automatically in all subclasses.

Might be solveable with AST macros :). Although you can still have problems with subclasses you don't know of during compile time. Doing separate compilation, libraries and so on.

> Object.factory only solve poorly one instance of this problem.

-- 
/Jacob Carlborg
November 14, 2013

On 13.11.2013 09:27, Benjamin Thaut wrote:
> Am 13.11.2013 08:31, schrieb Rainer Schuetze:
>>
>> - The DIP should state what happens to template instances. Assuming the
>> definition is marked "export", I guess instances will be dllexport if
>> they are compiled together with the module that contains the definition.
>> What will happen if it is instantiated, but the defining module is
>> merely imported?
>>
>> Rainer
>
> That is a very good point I also thought about. But because I'm not
> familiar with how exactly template instanciation works I can't really
> provide a solution for that.
>
> Does Walters recent template instanciation optimization also take into
> account template instaces of templates that are defined outside of the
> module that contains the template definition? I think the behaviour of
> exported template should mainly satisfy the needs of this optimization.


As far as I understand, the optimization avoids generating code for template instances only _created_ (not defined) by imported modules, e.g. when needed for semantic analysis inside the imported module, but never actually referenced by generated code by the root modules.

[OT: The problem of the current implementation is the detection of "only" in that definition, it fails too often leading to linker errors and the addition of that terrible -allinst switch. I had to disable the optimization for me before addition of that switch.]

With respect to export I guess the optimization doesn't change much as multiple instances of the same template instance still can be found in different object files (maybe even less predictable).

To avoid the trouble with templates, here is an idea for discussion:

- templates definitions by themselves are never dllexport/dllimport

- template instances are dllexport/dllimport with the proposed semantics of normal functions/variables if they are explicitely declared as "export" by an alias statement, e.g.

  export alias templ!int exported_tmpl_int;

- implicitely created template instances don't create dllexport versions, and use dllimport semantics if the declaration above is found in an import.

This would make it very explicit which module dllexports the template instance symbols. It is a bit like using typedef in C++ to ensure template instantiation.

One problem that might appear is that there are some conflicts if some modules import the "export alias" declaration, and some do not:

- In the dllexport case, it means that there are different COMDATs for the code and data of the template and it is undefined which one is chosen. (For Win64 COFF the exporting of the symbol is a separate directive, so it shouldn't be a problem, but I don't know for other object file formats.)

- It's worse for the dllimport case, as data accesses to template variables will sometimes use the additional indirection, sometimes not.
November 14, 2013
On 11/12/2013 1:46 PM, Martin Nowak wrote:
> On Sunday, 10 November 2013 at 19:34:32 UTC, Walter Bright wrote:
>> On 11/10/2013 4:13 AM, Benjamin Thaut wrote:
>> Actually, it isn't entirely clear to me why the moduleinfo needs to be exported.
>>
> That depends on whether using a module might require to link against the
> moduleinfo, currently it does. For example there is an importedModules property
> in ModuleInfo.

That's only used for initialization order.


>> The moduleinfo is needed to run the static ctors/dtors, etc., but that is
>> needed by the code internal to the dll that initializes the dll.
>
> Initialization order is not an issue here, the whole DLL (and all modules) is
> initialized before any DLL/exe that depends on it.

Right, so it shouldn't need to list it as an imported module.
November 14, 2013
On 11/12/2013 2:23 PM, Martin Nowak wrote:
> 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.

One possibility is modules listed on the command line are regarded as export==dllexport, and other modules as export==dllimport.

This of course means that functions may wind up going through the dllimport indirection even for calling functions in the same dll, but it should work.
November 14, 2013
Am 14.11.2013 11:28, schrieb Walter Bright:
> On 11/12/2013 2:23 PM, Martin Nowak wrote:
>
> One possibility is modules listed on the command line are regarded as
> export==dllexport, and other modules as export==dllimport.
>
> This of course means that functions may wind up going through the
> dllimport indirection even for calling functions in the same dll, but it
> should work.

That doesns't work for the case where a dll "A" uses a dll "B".
In that case export has to mean "dllexport" for all modules of A but "dllimport" for all modules of B.

-- 
Kind Regards
Benjamin Thaut