www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Partial classes

reply Manu <turkeyman gmail.com> writes:
I suspect this isn't possible in a compiled language like D, but I wonder
anyway, has anyone considered partial classes in D? Are they technically
possible?
How would they work? Would it depend on link-time code generation?
I can imagine an implementation where each 'part' occupies a separate
allocation, and some pointer in Object or somewhere like that (somewhere
near the typeinfo pointer) binds them together.

I often find myself wanting to add some extra pizazz to classes using
template/mixin magic, but I may not have control over the original code
where it is defined...

Jun 25 2012
next sibling parent reply "Regan Heath" <regan netmail.co.nz> writes:
On Mon, 25 Jun 2012 16:26:27 +0100, Manu <turkeyman gmail.com> wrote:

 I suspect this isn't possible in a compiled language like D, but I wonder
 anyway, has anyone considered partial classes in D? Are they technically
 possible?
 How would they work? Would it depend on link-time code generation?
 I can imagine an implementation where each 'part' occupies a separate
 allocation, and some pointer in Object or somewhere like that (somewhere
 near the typeinfo pointer) binds them together.

 I often find myself wanting to add some extra pizazz to classes using
 template/mixin magic, but I may not have control over the original code
 where it is defined...

compiled together. For example, I once tried to put a partial class into plain wont let you do this. derived from a DataContext (in one file), which I can extend and/or modify by implementing the rest of the partial class (in another file), in the same project (exe or dll) and if I compile them together I actually just get one merged class. D could easily implement a partial class feature with the restriction that they need to be compiled together. But IMO unless this is a trivial feature to implement, I wouldn't think it would be high on the priority list just yet. Partial classes make customizing auto generated (especially repeatedly auto generated) code much easier. #c uses them in it's form designer, placing all the designed code in a partial class in one file, and all user code in another file (in the same partial class). R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Jun 25 2012
parent reply "Kapps" <opantm2+spam gmail.com> writes:
Any reason that just using mixin(import("myclass.partial.d")) 
wouldn't work?
Jun 25 2012
parent "Regan Heath" <regan netmail.co.nz> writes:
On Tue, 26 Jun 2012 02:50:46 +0100, Kapps <opantm2+spam gmail.com> wrote:

 Any reason that just using mixin(import("myclass.partial.d")) wouldn't  
 work?
It /could/ work if you were careful about what you were mixing in, and [File1] partial class Foo { } [File2] partial class Foo { } And then, for example, the form builder gui would automatically add members and methods to File1 while user created content would be added by the user to File2. At compile time, the two files are compiled as one class. Alternately File1 may be produced by a tool like sqlmetal once, or multiple times while the user added content in File2 would remain completely under the users control. So, yes, in D we could have: [File1] partial class Foo { .. compiler/form builder content .. mixin(import("File2.d")) } [File2] void foo() { } But, note how File2 does not (cannot) have the class declaration, etc. Alternately you could go the other way.. [File1] partial class Foo { .. user content .. mixin(import("File2.d")) } [File2] .. compiler/form builder content .. So the compiler file has no class declaration, but then the user would have to be careful not to remove the mixin. i.e. 1. Partial classes must be in similarly named files i.e. foo_1.d and foo_2.d (where foo is user defined by _1 and _2 are mandatory). 2. Partial classes must be compiled on the same command line and produce foo.o (note _1 and _2 are dropped and only 1 object file is produced). .. and so on. I am no expert on compiling/linking so there may be complications to the feature, but essentially it could be as simple as compiling the first file, pretending you haven't seen the } ending the class definition, opening the next file and ignoring the "partial class" line and continuing as if they were 1 file. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Jun 26 2012
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/25/2012 05:26 PM, Manu wrote:
 I suspect this isn't possible in a compiled language like D, but I
 wonder anyway, has anyone considered partial classes in D? Are they
 technically possible?
 How would they work? Would it depend on link-time code generation?
Ideally yes, but it should be possible to initialize the relevant data structures at program load time. (druntime is already able to locate class type infos by their fully qualified names, so it should be feasible.)
 I can imagine an implementation where each 'part' occupies a separate
 allocation, and some pointer in Object or somewhere like that (somewhere
 near the typeinfo pointer) binds them together.

 I often find myself wanting to add some extra pizazz to classes using
 template/mixin magic, but I may not have control over the original code
 where it is defined...
How can you declare the class as partial if you do not have control over the original code?

I think the blocking issues are in the frontend: partial classes name spaces.
Jun 25 2012
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/25/2012 8:26 AM, Manu wrote:
 I suspect this isn't possible in a compiled language like D, but I wonder
 anyway, has anyone considered partial classes in D? Are they technically
possible?
 How would they work? Would it depend on link-time code generation?
 I can imagine an implementation where each 'part' occupies a separate
 allocation, and some pointer in Object or somewhere like that (somewhere near
 the typeinfo pointer) binds them together.
Are you talking about adding fields/functions to an arbitrary class without modifying the original definition of that class? If so, this would violate principles of encapsulation, and there'd be terrible consequences (as you could not rely on the class definition being the class definition without examining the entire code base). But, you can use UFCS to "add" member functions to an existing class. Adding data members can be done using the PIMPL technique, string mixins, or template mixins (but the original class needs to be designed for that).
Jun 25 2012
next sibling parent "Max Samukha" <maxsamukha gmail.com> writes:
On Monday, 25 June 2012 at 20:31:18 UTC, Walter Bright wrote:
 On 6/25/2012 8:26 AM, Manu wrote:
 I suspect this isn't possible in a compiled language like D, 
 but I wonder
 anyway, has anyone considered partial classes in D? Are they 
 technically possible?
 How would they work? Would it depend on link-time code 
 generation?
 I can imagine an implementation where each 'part' occupies a 
 separate
 allocation, and some pointer in Object or somewhere like that 
 (somewhere near
 the typeinfo pointer) binds them together.
Are you talking about adding fields/functions to an arbitrary class without modifying the original definition of that class? If so, this would violate principles of encapsulation, and there'd be terrible consequences (as you could not rely on the class definition being the class definition without examining the entire code base). But, you can use UFCS to "add" member functions to an existing class. Adding data members can be done using the PIMPL technique, string mixins, or template mixins (but the original class needs to be designed for that).
He's talking about this: http://msdn.microsoft.com/en-us/library/wa80x488(v=vs.80).aspx.
Jun 25 2012
prev sibling parent reply Manu <turkeyman gmail.com> writes:
On 25 June 2012 23:30, Walter Bright <newshound2 digitalmars.com> wrote:

 On 6/25/2012 8:26 AM, Manu wrote:

 I suspect this isn't possible in a compiled language like D, but I wonder
 anyway, has anyone considered partial classes in D? Are they technically
 possible?
 How would they work? Would it depend on link-time code generation?
 I can imagine an implementation where each 'part' occupies a separate
 allocation, and some pointer in Object or somewhere like that (somewhere
 near
 the typeinfo pointer) binds them together.
Are you talking about adding fields/functions to an arbitrary class without modifying the original definition of that class? If so, this would violate principles of encapsulation, and there'd be terrible consequences (as you could not rely on the class definition being the class definition without examining the entire code base).
But this is essentially no different than UFCS, except to me it feels like less of a hack than UFCS (which I personally find rather dirty by contrast). Additionally, often enough, that UFCS function depend on adding a piece of data to the object in addition to the functionality it implements. I don't think it's fair to say it would lead to terrible consequences, because it exists, and it's used very successfully in other languages. It's proven to be very useful. I have a recurring problem where, at the module level, using CTFE I can scan the module for information, and generate bindings of things to their related systems without lots of manual, messy, error-prone hook-up code. For me, I think this has been the single biggest advantage I've gotten from using D yet hands down. The problem is, it's limited to things in the global scope. Partial classes are the completion of that concept, allowing it to be applied to classes too. If when scanning a class I find it has relationships to given systems, I can't then magically add the appropriate binding to that system into the class. There are some fairly messy hack-arounds that kinda work, but they If it's not added to the class its self, all of the IDE features that I am always claiming are so critical don't really work. The self-documenting, self-writing, auto-completion, popup member/parameter helpers and stuff don't work. Also, quite to the contrary of what you say, separating the functionality that should be embedded in the class from the class, it breaks the encapsulation principle. The class should gain that property internally, not bolted on the side with some hacky mechanisms. But, you can use UFCS to "add" member functions to an existing class.

Indeed, but it's not quite the same.

Adding data members can be done using the PIMPL technique, string mixins,
 or template mixins (but the original class needs to be designed for that).
And that's basically the limitation I'd like to overcome. The fact something needs to be designed for it in advance; that is completely unrealistic. No 3rd party can ever anticipate what you might want to do. Whether you want to unintrusively extend some existing code, or you provide a library which can extend things in a general way.. If you can craft your partial extension in such a way than it integrates neatly with the 3rd party stuff you're using, that seems like a much more sensible approach, since it leaves the customisation to you, rather than the original author to attempt to anticipate... I really hate it when I have to butcher 3rd party code to add my bits. It makes it hard to maintain, if the author updates the code. Much nicer to extend it with my bit as a partial, and keep my code clinically separated.
Jun 25 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/25/2012 11:26 PM, Manu wrote:
 On 25 June 2012 23:30, Walter Bright <newshound2 digitalmars.com
 <mailto:newshound2 digitalmars.com>> wrote:

     On 6/25/2012 8:26 AM, Manu wrote:

         I suspect this isn't possible in a compiled language like D, but
         I wonder
         anyway, has anyone considered partial classes in D? Are they
         technically possible?
         How would they work? Would it depend on link-time code generation?
         I can imagine an implementation where each 'part' occupies a
         separate
         allocation, and some pointer in Object or somewhere like that
         (somewhere near
         the typeinfo pointer) binds them together.


     Are you talking about adding fields/functions to an arbitrary class
     without modifying the original definition of that class?

     If so, this would violate principles of encapsulation, and there'd
     be terrible consequences (as you could not rely on the class
     definition being the class definition without examining the entire
     code base).


 But this is essentially no different than UFCS, except to me it feels
 like less of a hack than UFCS (which I personally find rather dirty by
 contrast).
UFCS is just syntax. There is nothing deep/hacky/dirty behind it.
 Additionally, often enough, that UFCS function depend on
 adding a piece of data to the object in addition to the functionality it
 implements.
 I don't think it's fair to say it would lead to terrible consequences,
 because it exists, and it's used very successfully in other languages.
 It's proven to be very useful.
It is not fair to say it is not fair, because the interpretation he has given as a premise does not exist successfully in other languages. ;)
 I have a recurring problem where, at the module level, using CTFE I can
 scan the module for information, and generate bindings of things to
 their related systems without lots of manual, messy, error-prone hook-up
 code.
 For me, I think this has been the single biggest advantage I've gotten
 from using D yet hands down.
 The problem is, it's limited to things in the global scope. Partial
 classes are the completion of that concept, allowing it to be applied to
 classes too.
What mechanism do you use? You cannot add symbols to a module without having dedicated code in the module that does it. Why is the mechanism insufficient for classes? How would partial classes change the situation?
 If when scanning a class I find it has relationships to given systems, I
 can't then magically add the appropriate binding to that system into the
 class. There are some fairly messy hack-arounds that kinda work, but

It would be useful if you showed some pseudocode.
 If it's not added to the class its self, all of the IDE features that I
 am always claiming are so critical don't really work. The
 self-documenting, self-writing, auto-completion, popup member/parameter
 helpers and stuff don't work.
If the compiler can resolve symbols, in principle, an IDE should be able to list them.
 Also, quite to the contrary of what you say, separating the
 functionality that should be embedded in the class from the class, it
 breaks the encapsulation principle.  The class should gain that property
 internally, not bolted on the side with some hacky mechanisms.
It does not break the encapsulation principle. Embedded class functionality weakens data encapsulation.
     But, you can use UFCS to "add" member functions to an existing class.


 Indeed, but it's not quite the same.

     Adding data members can be done using the PIMPL technique, string
     mixins, or template mixins (but the original class needs to be
     designed for that).


 And that's basically the limitation I'd like to overcome. The fact
 something needs to be designed for it in advance; that is completely
 unrealistic.
public class ImACSharpClass{ } How to extend this class without changing the code? What I don't get yet is why adding 'partial' to the class definition is any better than adding 'import myadditionalfunctionality; mixin MyAdditionalFunctionality'. Is it about the separate compilation? Or is this just too 'hacky'?
 No 3rd party can ever anticipate what you might want to do. Whether you
 want to unintrusively extend some existing code, or you provide a
 library which can extend things in a general way.. If you can craft your
 partial extension in such a way than it integrates neatly with the 3rd
 party stuff you're using, that seems like a much more sensible approach,
 since it leaves the customisation to you, rather than the original
 author to attempt to anticipate...

 I really hate it when I have to butcher 3rd party code to add my bits.
 It makes it hard to maintain, if the author updates the code. Much nicer
 to extend it with my bit as a partial, and keep my code clinically
 separated.
You can always use aggregation or inheritance. An use case would be of help here.
Jun 25 2012
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/25/2012 2:26 PM, Manu wrote:
 On 25 June 2012 23:30, Walter Bright <newshound2 digitalmars.com
     Are you talking about adding fields/functions to an arbitrary class without
     modifying the original definition of that class?

     If so, this would violate principles of encapsulation, and there'd be
     terrible consequences (as you could not rely on the class definition being
     the class definition without examining the entire code base).


 But this is essentially no different than UFCS,
Adding behavior into an existing class that was not designed for it is, to me, like Ruby's "monkey-patching", since you could look at a class definition and have no clue if members were added by arbitrary other code or not. UFCS does it in a hygienic, encapsulated way.
 except to me it feels like less
 of a hack than UFCS (which I personally find rather dirty by contrast).
 Additionally, often enough, that UFCS function depend on adding a piece of data
 to the object in addition to the functionality it implements.
 I don't think it's fair to say it would lead to terrible consequences, because
 it exists, and it's used very successfully in other languages. It's proven to
be
 very useful.
Monkey-patching has, in Ruby, been popular and powerful. It has also turned out to be a disaster. It does not scale, and is not conducive to more than one person/team working on the code base.
 I have a recurring problem where, at the module level, using CTFE I can scan
the
 module for information, and generate bindings of things to their related
systems
 without lots of manual, messy, error-prone hook-up code.
 For me, I think this has been the single biggest advantage I've gotten from
 using D yet hands down.
 The problem is, it's limited to things in the global scope. Partial classes are
 the completion of that concept, allowing it to be applied to classes too.
 If when scanning a class I find it has relationships to given systems, I can't
 then magically add the appropriate binding to that system into the class. There
 are some fairly messy hack-arounds that kinda work, but they don't very very

 If it's not added to the class its self, all of the IDE features that I am
 always claiming are so critical don't really work. The self-documenting,
 self-writing, auto-completion, popup member/parameter helpers and stuff don't
work.
 Also, quite to the contrary of what you say, separating the functionality that
 should be embedded in the class from the class, it breaks the encapsulation
 principle. The class should gain that property internally, not bolted on the
 side with some hacky mechanisms.

     But, you can use UFCS to "add" member functions to an existing class.


 Indeed, but it's not quite the same.
You're right, and I'd argue that UFCS is hygienic, monkey-patching is not.
     Adding data members can be done using the PIMPL technique, string mixins,
or
     template mixins (but the original class needs to be designed for that).


 And that's basically the limitation I'd like to overcome. The fact something
 needs to be designed for it in advance; that is completely unrealistic.
 No 3rd party can ever anticipate what you might want to do. Whether you want to
 unintrusively extend some existing code, or you provide a library which can
 extend things in a general way.. If you can craft your partial extension in
such
 a way than it integrates neatly with the 3rd party stuff you're using, that
 seems like a much more sensible approach, since it leaves the customisation to
 you, rather than the original author to attempt to anticipate...
That violates encapsulation because the 3rd party library code may have subtle dependencies on it not being extended, like using a .sizeof. Or, what to do if two different pieces of source code extend a class in different ways? What to do if new overloads are added, and some code sees those overloads and some do not?
 I really hate it when I have to butcher 3rd party code to add my bits. It makes
 it hard to maintain, if the author updates the code. Much nicer to extend it
 with my bit as a partial, and keep my code clinically separated.
anyway - isn't that the same as inserting a template/string/import mixin or pimpl? Adding functionality for classes is also straightforward - derive from it. Adding functionality to structs is done with alias this.
Jun 25 2012
next sibling parent "Max Samukha" <maxsamukha gmail.com> writes:
On Monday, 25 June 2012 at 23:44:09 UTC, Walter Bright wrote:


 class definition anyway - isn't that the same as inserting a 
 template/string/import mixin or pimpl?
That is not exactly the same. The important difference is that partial definitions can have attributes, interfaces, nested partial definitions etc., which will be merged in the resulting definition. That is not achievable with mixins or pimpl in a satisfactory way. See http://msdn.microsoft.com/en-us/library/wa80x488(v=vs.80).aspx. Not arguing for this feature. Simply noting that it is NOT the same as mixins/pimpl.
Jun 25 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-06-26 01:43, Walter Bright wrote:

 Monkey-patching has, in Ruby, been popular and powerful. It has also
 turned out to be a disaster. It does not scale, and is not conducive to
 more than one person/team working on the code base.
I have only found it being very useful. I have never found it to be a disaster. Have you ever used Ruby? Ruby on Rails has to be the most popular Ruby library/framework and it adds a lot of new functionality to existing classes in the standard library. But just as with everything else you have to be responsible. In Ruby you can replace arbitrary methods and classes, even in the standard library. In D you can overwrite an arbitrary piece of memory. -- /Jacob Carlborg
Jun 26 2012
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 6/26/2012 3:53 AM, Jacob Carlborg wrote:
 On 2012-06-26 01:43, Walter Bright wrote:

 Monkey-patching has, in Ruby, been popular and powerful. It has also
 turned out to be a disaster. It does not scale, and is not conducive to
 more than one person/team working on the code base.
I have only found it being very useful. I have never found it to be a disaster. Have you ever used Ruby?
Not much, but I've read accounts from people who have who say that monkey-patching doesn't scale.
 Ruby on Rails has to be the most popular Ruby library/framework
PHP is popular, too.
 and it adds a
 lot of new functionality to existing classes in the standard library.

 But just as with everything else you have to be responsible.
A language should not encourage bad behavior, nor should it make code unreasonably difficult to reason about.
 In Ruby you can
 replace arbitrary methods and classes, even in the standard library. In D you
 can overwrite an arbitrary piece of memory.
Not when using safe code, you can't.
Jun 26 2012
parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 06/26/12 20:21, Walter Bright wrote:
 On 6/26/2012 3:53 AM, Jacob Carlborg wrote:
 replace arbitrary methods and classes, even in the standard library. In D you
 can overwrite an arbitrary piece of memory.
Not when using safe code, you can't.
void poke(T)(size_t addr, T val) safe pure { T* ptr; ptr[addr/T.sizeof] = val; } int i = 42; void main() safe { writeln(i); auto whatever = cast(size_t)&i; poke(whatever, 666); writeln(i); poke(0, 0); } void writeln(A...)(A a) trusted { import std.stdio; writeln(a); } artur
Jun 26 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/26/2012 09:29 PM, Artur Skawina wrote:
 On 06/26/12 20:21, Walter Bright wrote:
 On 6/26/2012 3:53 AM, Jacob Carlborg wrote:
 replace arbitrary methods and classes, even in the standard library. In D you
 can overwrite an arbitrary piece of memory.
Not when using safe code, you can't.
void poke(T)(size_t addr, T val) safe pure { T* ptr; ptr[addr/T.sizeof] = val; } int i = 42; void main() safe { writeln(i); auto whatever = cast(size_t)&i; poke(whatever, 666); writeln(i); poke(0, 0); } void writeln(A...)(A a) trusted { import std.stdio; writeln(a); } artur
This is not legal D code. (pointer indexing is unsafe)
Jun 26 2012
parent Walter Bright <newshound2 digitalmars.com> writes:
On 6/26/2012 12:52 PM, Timon Gehr wrote:
 On 06/26/2012 09:29 PM, Artur Skawina wrote:
 On 06/26/12 20:21, Walter Bright wrote:
 On 6/26/2012 3:53 AM, Jacob Carlborg wrote:
 replace arbitrary methods and classes, even in the standard library. In D you
 can overwrite an arbitrary piece of memory.
Not when using safe code, you can't.
void poke(T)(size_t addr, T val) safe pure { T* ptr; ptr[addr/T.sizeof] = val; } int i = 42; void main() safe { writeln(i); auto whatever = cast(size_t)&i; poke(whatever, 666); writeln(i); poke(0, 0); } void writeln(A...)(A a) trusted { import std.stdio; writeln(a); } artur
This is not legal D code. (pointer indexing is unsafe)
If the compiler doesn't give an error on that, it's a compiler bug, not a language problem.
Jun 26 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-06-25 23:26, Manu wrote:

 And that's basically the limitation I'd like to overcome. The fact
 something needs to be designed for it in advance; that is completely
 unrealistic.
 No 3rd party can ever anticipate what you might want to do. Whether you
 want to unintrusively extend some existing code, or you provide a
 library which can extend things in a general way.. If you can craft your
 partial extension in such a way than it integrates neatly with the 3rd
 party stuff you're using, that seems like a much more sensible approach,
 since it leaves the customisation to you, rather than the original
 author to attempt to anticipate...

 I really hate it when I have to butcher 3rd party code to add my bits.
 It makes it hard to maintain, if the author updates the code. Much nicer
 to extend it with my bit as a partial, and keep my code clinically
 separated.
Isn't it the same with partial classes? What if the third party class hasn't been marked with "partial". -- /Jacob Carlborg
Jun 26 2012