While the concept sounds good on the surface, there seems an awful lot
of baggage associated with it.
Have you had a look at the work done by the Modules SG?
If you go that road, I suggest looking at Modula 3 and its "partial revelations", ie the possibility for a component to provides different interfaces to different customers.
> maybe somebody can join and help with this following brainstorming, may
> sound naive, but would love to hear opinions.
Are you familiar with Objective-C? If not, I recommend researching
Objective-C interfaces, implementations, categories, and class
extensions to help flesh out your idea.
What would sizeof(A) produce in a translation unit that observes only
the interface (white) declaration?
Would this require a dynamic sizeof
similar to that required for C99 variable length arrays? (I think the
need for a dynamic sizeof is one of the issues that have prevented
variable length arrays being added to C++).
Would class data members of these split class types be allowed when only
the interface (white) declaration is present in a translation unit? If
so, what would be the result of sizeof(X) for such a class?
Without a static sizeof, you can't:
- use operator new
- use make_shared or make_unique
- declare the object on the stack
- use it as a member of another object
> Yes you could. The size and offset needed though would be calculated at
> runtime with similare mechasism like -fpic
More like virtual inheritance instead of position-independent code.
Also possible, but just not the way I envisioned it. Loading it from a very
different page of memory may be slower than keeping it local and just
referencing each dynamic item by a pointer, like a virtual base.
> Referencing each dynamic item by a pointer : you are proposing that dynamic
> items shall be allocated separately and keep a pointer like in the case of
> opaque pointers?
No, I am not proposing that. First of all, I am not proposing anything.
personally don't think your proposal will fly...
But if it were to be implemented, I'd expect it to be done like a class with
virtual bases: the allocator allocates a block of memory with sufficient size
for all of the dynamic objects inside,
which it calculates at runtime by
adding up the sizes of each one, and initialises a helper pointer to those
objects.
The other solution is to create a "dynamic table" of the class, which like the
virtual table, is associated one per class. This table would contain the size
of the full class and the offsets of each of the dynamic-sized members. The
problem here is initialising this table, since it can only be done at runtime,
it has to be done on program load.
The other option would be for the compiler to produce an interface
file containing the necessary details.
struct MyObject_real
{
MyObject_vtable *_vptr;
SomeOther *_vbase;
Foo *foo;
Bar *bar;
int i;
int j;
void *d;
SomeOther _vbase_space;
// plus space for Foo and Bar
};
The code that allocates MyObject needs to take sizeof(MyObject_real) and add
the dynamic sizes of Foo and Bar. The difference between that and the allocated
space for the virtual base is that the size of the former isn't known at
compile time.
On Friday 06 February 2015 18:15:02 mobi phil wrote:
> so, this topic can be forgotten, nobody bites? ;)
You haven't written a proposal.
I meant that you did not write a paper and submit to the committee forOn Saturday 07 February 2015 00:57:53 mobi phil wrote:
> On Fri, Feb 6, 2015 at 11:22 PM, Thiago Macieira <thi...@macieira.org>
>
> wrote:
> > On Friday 06 February 2015 18:15:02 mobi phil wrote:
> > > so, this topic can be forgotten, nobody bites? ;)
> >
> > You haven't written a proposal.
>
> Sorry, do not understand this. How would you pretend there was no proposal
> while you reacted to it yourself....
consideration.
I think your idea has merit. It makes sense to present it and talk to the
people doing Modules. Some aspects of it could be adopted there.
On 7 February 2015 at 16:06, <gmis...@gmail.com> wrote:
>> While I do not know exactly the formal procedure, I do not think it is
>> worth the effort to write a formal paper unless some of the honorable
>> members of the honorable committee would show minimum interest to ever
>> consider it. The reason of the brainstorming is to find together weaknesses
>> of the model and solutions for them.
> I agree
As far as I understand it, the idea deals with being able to express
interface-implementation splits in a way that doesn't incur size/abstraction
penalty. Some aspects of that are handled by modules, some probably
aren't.
Overall, the "in size" "physical design" aspect of having to
state the types of members in a class definition can indeed be problematic
in the sense that you have to commit to the types in a class definition
regardless of whether the types are ever used by clients. There are
work-arounds(*) for that, so the question is whether language support
for such a facility is truly necessary and/or worth the cost of it.
(*) The work-arounds aren't necessarily easy - having a data buffer
in a class and having pimpl-side implementations know the actual
type of objects stored in such a buffer require proper alignment
and proper lifetime handling, which can be non-trivial.
On 7 February 2015 at 16:06, <gmis...@gmail.com> wrote:
>> While I do not know exactly the formal procedure, I do not think it is
>> worth the effort to write a formal paper unless some of the honorable
>> members of the honorable committee would show minimum interest to ever
>> consider it. The reason of the brainstorming is to find together weaknesses
>> of the model and solutions for them.
> I agree
As far as I understand it, the idea deals with being able to express
interface-implementation splits in a way that doesn't incur size/abstraction
penalty. Some aspects of that are handled by modules, some probably
aren't.If you change the class definition, you need to recompile module + everything depends on module.
If you split the stuff into to, you need to recompile only if you change the real interface towards the rest of the world.
In my experience you spend 90% of time doing useless recompiles just because you need to ad a damm' private method. If it is private why do I need to recompile billions of lines of code in client code?
While this is not the only benefit the proposal would bring, it is the only one that would have some way to deal with modules. Unfortunately though the same benefit could not be achieved by modules.
Overall, the "in size" "physical design" aspect of having to
state the types of members in a class definition can indeed be problematic
in the sense that you have to commit to the types in a class definition
regardless of whether the types are ever used by clients. There are
work-arounds(*) for that, so the question is whether language support
for such a facility is truly necessary and/or worth the cost of it.
(*) The work-arounds aren't necessarily easy - having a data buffer
in a class and having pimpl-side implementations know the actual
type of objects stored in such a buffer require proper alignment
and proper lifetime handling, which can be non-trivial.
Of course there are work-arounds. Pimpl would be just an annoying hack that would make inheritance difficult. Alignment and similar problems should be the compilers problem.
"there is a workaround", pattern is often used, as most of the cases there is a workaround. There is a workaround for any aspect for which C++ tries to prove that it is inferior to C,
including object oriented programming, type safety, templates etc. You can implement dynamic type checking and you will be on the safe side. You can implement constructs that mimic templates at a very high cost, including some trivial text based templates etc. etc. For everything there is a workaround. Unfortunately most of the cases it turns out that work-arounds are ugly hacks with serious negative consequences.
For me the equation is simple:-> how many people/projects are using pimple?-> why are they using pimple?-> what is overhead to implement pimple for each class?-> how much this overhead compromises the readibility of the code?-> how many people/projects avoided pimple, just because pimple is ugly and preferred to discard advantages concerning the binary interface
I would expect modules would bring this.If you split the stuff into to, you need to recompile only if you change the real interface towards the rest of the world.
Why? What is missing in modules so that we can achieve it?While this is not the only benefit the proposal would bring, it is the only one that would have some way to deal with modules. Unfortunately though the same benefit could not be achieved by modules.
Don't forget that C++ includes C, so that anything you can do with C you can do with C++.Of course there are work-arounds. Pimpl would be just an annoying hack that would make inheritance difficult. Alignment and similar problems should be the compilers problem.
"there is a workaround", pattern is often used, as most of the cases there is a workaround. There is a workaround for any aspect for which C++ tries to prove that it is inferior to C,
I would expect modules would bring this.If you split the stuff into to, you need to recompile only if you change the real interface towards the rest of the world.
well, while I do not know in depth the modules proposal, I would rather bet, that it will not be able to do the impossible. I have doubts that it would be so clever, that will not force clients to recompile once you add the declaration of a private method.
Why? What is missing in modules so that we can achieve it?While this is not the only benefit the proposal would bring, it is the only one that would have some way to deal with modules. Unfortunately though the same benefit could not be achieved by modules.
see above: IMHO modules will not be able to deal with-> do not recompile client code if you add private method-> do not recompile if you change class internal data-> recompile only if the interface of a class changes, in best case if the method definition that client code depends on changes.
Please note that this black-white proposal does not mean that all classes have to behave this "dynamic" way.
<snip>
I don't think pimpl is the idiom needed to split the back and the white parts of a class. IMHO, it is more the backdoor idiom that is needed. The backdoor is the black part of your proposal.
For me the equation is simple:-> how many people/projects are using pimple?-> why are they using pimple?-> what is overhead to implement pimple for each class?-> how much this overhead compromises the readibility of the code?-> how many people/projects avoided pimple, just because pimple is ugly and preferred to discard advantages concerning the binary interface
<snip>
I'm all for a future C++ in which we don't need this idiom, and I expect that the Module proposal would provide it.
while you remove the problem of pimple, you introduce sthg. else, which my proposal tries to solve. You are strongly depending on this N. Too loosen a bit this dependency you could make at the beginning this N enough big, but that would lead to waste of memory.
There is not big or small, just are equals or not. This N, should be provided by the compiler from the module definition as well as all other public and protected functions.
My proposal covers the fact that this "N" is practically replaced at runtime, with the real size.
c++std-...@accu.orgVicente
Le 08/02/15 13:23, mobi phil a écrit :
IMO, this should be possible and so it is a QOI. Only if the implementers consider that this wouldn't be possible or too complex we would need to adapt the proposal.I would expect modules would bring this.If you split the stuff into to, you need to recompile only if you change the real interface towards the rest of the world.
well, while I do not know in depth the modules proposal, I would rather bet, that it will not be able to do the impossible. I have doubts that it would be so clever, that will not force clients to recompile once you add the declaration of a private method.
IMHO, it should be easier to ensure that the module proposal is able to do it that adding your alternative approach.Why? What is missing in modules so that we can achieve it?While this is not the only benefit the proposal would bring, it is the only one that would have some way to deal with modules. Unfortunately though the same benefit could not be achieved by modules.
see above: IMHO modules will not be able to deal with-> do not recompile client code if you add private method-> do not recompile if you change class internal data-> recompile only if the interface of a class changes, in best case if the method definition that client code depends on changes.
I don't see anything dynamic in the behavior you have defined.Please note that this black-white proposal does not mean that all classes have to behave this "dynamic" way.
There is not big or small, just are equals or not. This N, should be provided by the compiler from the module definition as well as all other public and protected functions.while you remove the problem of pimple, you introduce sthg. else, which my proposal tries to solve. You are strongly depending on this N. Too loosen a bit this dependency you could make at the beginning this N enough big, but that would lead to waste of memory.
We don't need it at run-time, but at compile time, and IMO, the Module proposal should be such that such implementation is possible.My proposal covers the fact that this "N" is practically replaced at runtime, with the real size.
After reading the module proposal, it seams that, they are not addressing this problem. I suggest you to join the Module ML and request for the requirements you are looking for (not the solutions). Maybe your white/black split could be the solution.
c++std-...@accu.org
On Sunday 08 February 2015 18:14:26 mobi phil wrote:
> If you changed the header, the timestamp, checksum, or whatsoever way you
> would implement dependencies, the source file that depends on the header in
> question will have to be rebuilt. This must be true even in case where you
> add a private method, unless a special file is generated for dependencies
> that reflect only really "public" stuff from headers.
Unless, of course, that class has friends. In which case, even private changes
will require rebuilding.
> While reducing dependencies is one of the goals of my approach/proposal I
> really doubt that handling private data changes in headers will be delt
> with modules. For simple reason that any source file that depends on the
> definition of the class (due to sizeof()) will need to recompile once the
> size of the class changes. In my proposal this dependency is postponed till
> runtime.
Your idea, not proposal. You need to do a little more work to make it a
proposal, including writing a paper and presenting it in a committee meeting.
Or convincing someone to do it for you.
> > After reading the module proposal, it seams that, they are not addressing
> > this problem. I suggest you to join the Module ML and request for the
> > requirements you are looking for (not the solutions). Maybe your
> > white/black split could be the solution.
> >
> > c++std-...@accu.org
> >
> > No problem to help there, but personally I fail to see that this could be
>
> done with modules...
Are you saying that modules would make it impossible to implement your
suggestion?
Because if you aren't saying that, then you're missing the point. We're not
saying that modules is doing what you suggested. We are saying that you should
join the modules discussion so that your solution gets worked into the modules
proposal.
On Sunday 08 February 2015 19:17:37 mobi phil wrote:
> > On Sunday 08 February 2015 18:14:26 mobi phil wrote:
> > Unless, of course, that class has friends. In which case, even private
> > changes
> > will require rebuilding.
>
> Friendship as always should be sometimes reconsidered. If not really
> necessary for performance reason, just use getters/setters.
That's advice. Unless forbid the practice, the advice can be ignored and you
have to deal with it.
It's irrelevant whether it's a bad practice or not.
Though could reformulate the
> original post, do not feel at the moment it would be worth to go into a
> deep analyzis if the added value is not recognized.
What recognition are you expecting before you go further?
Understood.
I still recommend talking to the people doing modules because they may have
other points to bring up and they're the right people to help you with your
suggestion.
I have two qualms about the proposal: one, which we discussed, is the runtime
overhead which may be too great, greater than the use of d pointers (pimpl).
The other is that I can't use for a long time. Let me put it this way: if this
showed up for C++17, we might be able to start relying on it in Qt by 2025.
Other than that, the idea is interesting.
If you want more feedback, write a paper.
I will add this quoting the proposal:
"Runtime Performance
Moving an existing code to a brave new module world, or writing new codes with modules, should not in any way degrade its runtime performance characteristics. In particular, we do not seek a module system requiring a compiler to perform automatic “boxing” of object representation (exposed in class private members) –in attempts to reducing re-compilation– via opaque data pointers a la ` pImpl idiom."
Respect to the visibility issue, I would like to preserve Runtime Performance also: Moving an existing code to a brave new visibility aware world, or writing new codes with visibility concerns, should not in any way degrade its runtime performance characteristics."
I'm not saying that I'm against any visibility solution that doesn't preserve runtime performance, just that the performance aspect must be considered.
This is an attractive alternative to pointer-based PIMPL, though it would require sweeping modifications to be made across every compliant loader/toolset.
That said, I still like it.
However, it doesn't seem to address re-using the same interface for multiple implementations simultaneously (exposing "new" through the interface layer constrains it to a single implementation).
*snip*
This is an attractive alternative to pointer-based PIMPL, though it would require sweeping modifications to be made across every compliant loader/toolset.
That said, I still like it.
However, it doesn't seem to address re-using the same interface for multiple implementations simultaneously (exposing "new" through the interface layer constrains it to a single implementation).
Another issue is version discrepancy: What metadata must be stored in external module containing all the "black" in order to ensure that the addition of new members to that layer do not cause undefined behavior when linked against an older "white" that doesn't know about them? There needs to be a way to verify a new "black" against an already compiled "white" during compilation, which seems to indicate the need for a large amount of metadata...
These concerns stem from a number of problems I've been facing lately:
Say we need to display the same dataset on a workstation monitor and through a projector.
The monitor is connected through an Nvidia adapter, and the projector through an old ATI.
We have to create one rendering context per adapter, as moving a window from the workstation display to the projector will crash or result in garbage (unless all rendering is done with GDI).
Both contexts have different feature sets resulting in different "black" layers, however the "white" layer looks the same for both.
The obvious solution is PIMPL, though there is a lot of work involved in maintaining the parallel sets of types required to realize this.
After a small change in the interface, resolving version discrepancies for every affected module slows development to a crawl.
If you don't mind me horribly abusing the terminology here...
From what I gather: "white" is the interface and "black" is the implementation (duh). Instead of the pointer-to-PIMPL, this would work kinda like partial classes in C#: The loader fills out offset/size details at load time.
The display example is just one of several (Nvidia and ATI crap don't get along, so everything breaks, but that's beside the point).
Rebuilding isn't the problem: Its validating changes that have to be made on a per-implementation basis.
The problem, in general, is that there are numerous interfaces that the "core" application is meant to work with, and those interfaces are backed by implementations known only at runtime (plugins).
This is why I asked about re-using interfaces: All the "whites" would be in a central codebase (in some cases, compiled and distributed to end-users who write their own plugins), and all the "blacks" would be implemented on a per-plugin/component basis. Multiple plugins that back the same interface would need to be loaded simultaneously.
The problem with the distribution of the "white" binary is that users will need/want to add members to the "black" halves they are writing, creating part of the "version discrepancy" issue I was describing (this also happens when a new "white" binary is distributed that must work with all existing "blacks").
In the display example, we'd need two different graphics backends: Usually the small vs. large display or comparing OpenGL and D3D with synchronized resources (CAD shapes w/ optimized representations for each).
D3D is very, very different from OpenGL, so the "black" half of either would need to be updated by hand. Add to that OpenGL's abomination of an "extension" system, and you have a swampland of implementations to fill in.
If your proposal is supposed to work statically, then I've completely missed the boat (wouldn't surprise me, I've been looking for a way to simplify these messes for years)...
class white button
{
public:
// Speculative data members
// (roughly equivalent to properties)
string title;
visual_style &style;
};
class black button
{
public:
string title;
HWND hWnd;
visual_style &style;
// Etc...
};
// Speculative interface
class virtual button
{
public:
string title;
visual_style &style;
// Note: We can still have virtual methods.
};
// Concrete definition
class override button
{
public:
// At least "string title" and "visual_style &style"
// must be declared. Anything else is free game.
string title;
HWND hWnd;
visual_style &style;
};
class white button
{
public:
// Speculative data members
// (roughly equivalent to properties)
virtual string title; /* note I added here virtual */ // // it would be equally possible string getTitle(); /* note I added here virtual */
visual_style &style;
};
class black button
{
public:
string title; /* the linker will make this public through the virtual from white */
HWND hWnd;
visual_style &style;
// Etc...
};
Accessing a member through a speculative interface would merely involve fetching an offset from a vtable. Much like static binding of a virtual method call, it is also possible to deduce a member offset statically if the concrete definition is available.
Inheriting from a virtual class makes the result virtual and requires that the override inherit from the same bases (possibly in the same order). It might be reasonable to automatically attach that inheritance to the override when its definition is encountered.
As the override might inherit from additional bases, this makes chasing down "repeated base" errors a bit more involved.
Unfortunately, using this model, it must be illegal to instantiate or apply sizeof() to a "virtual" class if an "override" is not visible in the same translation unit.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
It's been a while, but I think I recall the general gist. I think one of
us is missing something, however. I get the black/white concept when you
separate the interface from the implementation (isn't that the point?).
What I *don't* get is what it means to use this feature when the two are
*not* separated.
(In particular, as per my question, what would be the
use case for that and how would it differ from a "regular" class?)
*snip*
On 2015-02-17 12:16, Chris Gary wrote:
> I would also like to add that, unless there is a reasonable way to combine
> a "white" and "black" into the same definition, this actually *forces* the
> two to be separated.
How would such a combination be different from a regular class?
--
Matthew
That, or simply forbidding sizeof() or alignof() to be used on an interface in the context of a template, which makes the idea incompatible with half the language...
The idea would be that it would simultaneously define an interface and implementation, while allowing other implementations to be defined later. This would reduce repetition, as a separate "black" would not have to be defined right away.
Unless there is some way to add a "pure" specifier, the absence of which would allow a "white" definition to double as "black".
I still have a problem with needing to resolve sizeof() at link time: Using sizeof() is critical for templates that decide things like whether or not an instance will fit in a small aligned buffer versus needing heap allocation.
Obviously, alignment becomes a problem, as we might have some member with larger than alignof(double) requirement (e.g. AVX tuple). I don't think this can be dealt with efficiently at link time, as it would basically require all template "algorithms" to be recorded as bytecode somehow. That, or simply forbidding sizeof() or alignof() to be used on an interface in the context of a template, which makes the idea incompatible with half the language...
Concerning keywords: I don't really care what is chosen, just as long as they don't turn nested definitions and the like into keyword soup or become easily confused with other commonly-defined symbols (such as color enums). My policy about keywords is that the result needs to be reasonably readable as monochrome text...
I exaggerated a bit there... Let me clarify: If a "white" can double as a "black" (or there is a compatible "black" in the TU), then sizeof() and alignof() are well-defined, but it absolutely must be deduced at compile time.
The case where it can't be used in a template really isn't that different than applying sizeof() to an incomplete type (pure "white" is fundamentally incomplete)...
still needs to be analyzed.. but I tend to think the same. If alloca is standard then class could be allocated on stack. I still fail to see how call by value could be solved if sizeof is not known.
Not sure if I mentioned in my original post, but this black/white story is mainly intended for "big classes" which will not be candidate for call by value.
still needs to be analyzed.. but I tend to think the same. If alloca is standard then class could be allocated on stack. I still fail to see how call by value could be solved if sizeof is not known.
The compiler has to reduce a 'sizeof(button)' or 'alignof(button)' to a constant integer and fold any dependent constant expressions or templates dependent thereupon before sending the whole thing to code generation. It is not possible to know size or alignment if the precise content and layout of a 'button' is only speculative or unspecified.
Not sure if I mentioned in my original post, but this black/white story is mainly intended for "big classes" which will not be candidate for call by value.
Classes are treated as general categories, regardless of size. This proposal will need to work for classes of any size, even empty ones.
*snip* Thus cannot see too much reason not to have separate black. can you give an example pls.
class public button
{
public:
string text;
drawing::color color;
};
[[dllimport]]
button *make_special_button();
void verb()
{
// WYSIWYG instantiation of button.
//
// sizeof(button) MUST reduce to a constant integer at compile time!
//
button btn{};
button *btn_ptr = make_special_button();
btn_ptr->text = "Press me!";
}
// Problem:
//
// What if more than one of these are visible in the same TU?
// Use the most recent definition?
// If they all have the same layout and member ordering, don't complain?
//
class private button
{
public:
// To save typing, this automatically injects
// members that aren't explicitly declared
// in the same declaration order, before any
// member declared in "private"
// "text" implicitly declared before what follows.
HWND hWnd;
drawing::color color;
};
[[dllexport]]
button *make_special_button()
{
return new button{/*Create window, set text, blah...*/};
}
*snip*
The point I tried to make is that not knowing sizeof() at compilation time may may cause some implementation issues for for call by value or reference. If it turns out that will be impossible to implement call by value or by reference, it should not be considered as a catastrophe and the proposal rejected for this reason. But this may be just a false alarm due to my limited knowledge of how call by reference and by value is translated. Once I have time will have a look on how code is generated for different layouts etc.
*snip* Thus cannot see too much reason not to have separate black. can you give an example pls.
Consumer:
class public button
{
public:
string text; // MOBIPHIL: still needs to be decided if this means a "real" data that extends the interface or automatically a "virtual" one that needs to be resolved by a black
drawing::color color;
};
[[dllimport]]
button *make_special_button();
void verb()
{
// WYSIWYG instantiation of button.
//
// sizeof(button) MUST reduce to a constant integer at compile time! MOBIPHIL: not necessarily! if behind the scene the compiler could generate sthg. like char *buffer = alloca(button_sizeof()); new (buffer) blahblah...
//
button btn{};
button *btn_ptr = make_special_button();
btn_ptr->text = "Press me!";
}
PIMPL producer:
// Problem:
//
// What if more than one of these are visible in the same TU?
// Use the most recent definition? MOBIPHIL: you will get duplicated symbol for symbols (either functions or globals, depending on the implementation) that are defining the sizeof and offsets of visible members
// If they all have the same layout and member ordering, don't complain?
//
class private button
{
public:
// To save typing, this automatically injects
// members that aren't explicitly declared
// in the same declaration order, before any
// member declared in "private" MOBIPHIL: no real objections against injection... see further comment below
// "text" implicitly declared before what follows.
HWND hWnd;
drawing::color color;
};
[[dllexport]]
button *make_special_button()
{
return new button{/*Create window, set text, blah...*/};
}
*snip*The point I tried to make is that not knowing sizeof() at compilation time may may cause some implementation issues for for call by value or reference. If it turns out that will be impossible to implement call by value or by reference, it should not be considered as a catastrophe and the proposal rejected for this reason. But this may be just a false alarm due to my limited knowledge of how call by reference and by value is translated. Once I have time will have a look on how code is generated for different layouts etc.
This is why I keep repeating "sizeof() must reduce to a constant at compile time." As templates constitute what is basically a functional language of categories and simple integer expressions, we would need a way to modify already-compiled binaries to accept a type with an unknown layout and alignment (want some more bytecode with your bytecode?). I believe similar issues were encountered with "export templates"... Imagine some exported dependent template that does not terminate for some odd size of a type; how difficult it might be to isolate that kind of bug (unless we have a solution to the halting problem somewhere). So, keeping things simple, we either forbid sizeof(), new, etc.. without a visible PIMPL, or just invoke WYSIWYG.
namespace _impl{
using AnySmallBfr = uintptr_t[3];
struct _basic_any_blob
{
virtual void _destroy() noexcept = 0;
// Destructor not called!
};
template<
typename InnerType
bool isSmall = (
sizeof(InnerType) <= sizeof(AnySmallBfr)
)
>
struct _any_blob : _basic_any_blob
{
InnerType _that;
void _destroy() noexcept override
{this->_that->~InnerType();}
// Rest of implementation
};
template<typename InnerType>
struct _any_blob<InnerType, false>
{
// Too big, need to allocate separately
InnerType *_that_ptr;
void _destroy() noexcept override
{delete this->_that_ptr;}
// Rest of implementation
};
}// namespace _impl
class any
{
_impl::AnySmallBfr _small_bfr;
public:
template<typename ValueType>
any(ValueType &&value)
{
// Decides between small and large
// backing store.
//
// If sizeof(ValueType) <= sizeof(_small_bfr),
// placement-new into _small_bfr.
// This should compile statically, but...
//
// Are you suggesting we automate code generation
// to handle structures like _any_blob<> parameterized
// by "white" types?
//
new(this->_small_bfr) _impl::_any_blob<
decay<ValueType>
>{forward<ValueType>(value)};
}
~any() noexcept
{
reinterpret_cast<_impl::_basic_any_blob &>(
this->_small_bfr
)._destroy();
}
};
class public thing
{
public:
string in_thing;
};
void verb()
{
// What happens if the resulting object's
// size depends on something loaded externally?
//
// Also: What if we have multiple implementations linked? Which 'thing' is chosen?
//
any wut = thing{};
}
// Too big for internal buffer of 'any'
//
class private thing
{
public:
string in_thing;
int hidden_int;
float hidden_float;
char hidden_chars[16];
};
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
I can tell you right now: without knowing the size, passing by value in the
current way "pass-by-value" is understood will be impossible, period.
Passing by reference or by pointer should be possible, since those already
work even on incomplete types.
A solution for the by-value case is to treat it as passing by
pointer/reference in the ABI. That is, in most ABIs, the compiler will have to
reserve stack space for the dynamic size, copy the content, then pass the
address of that space.
Black or white types will always need to be passed by hidden reference.
How many registers do you reserve for the structure if you don't know its
size? Selecting the registers dynamically means all other parameters would be
dynamically determined, which seems to me to be horribly inefficient.
> to have reduced the "impossible" to the handicap of not being able to pass
> in registers. I would love to have time to read your blog and other
> millions of books, article on the topic.
Well, if you're not going to read up on the subject, how can we discuss the
subject?
> Best is to look at generated code,
> no blog/book/video/etc. can tell me more than. What I see so far that it is
> feasable. If some mini optimization opportunities are lost, well, you
> always have to tread sthg. for sthg. else...
How do you think I came up with the content of the blog? By compiling and
generating code, plus reading the ABI manuals.
> I am personally ok with this little "disadvantage". If I want to hunt for
> that little piece of cake, then I will move my blacks to the white and get
> it once the project reached a stable phase. I am also thinking about some
> details on how to move black back if optimization is to be achieved.
Once a black box, always a black box: as you don't know the other side, you
must assume the other side doesn't have access to the white box.
> Do not forget that QT pimple object cannot be passed in registers...
> Because he is still a pointer...
The Private class can't, but the outer, public class could be.
Though for Qt, classes that can be passed in registers are rare because most
are either ref-counted or non-copyable and neither of those types can be
passed in registers.
> So, lets take things easy. Let's do not adventure to far, before we did not
> fix simple things. Let's do not optimize before we agreed on basic stuff...
> Would alloca knowing the size from a function or global variable solve the
> problem of sizeof of black?
Yes. if the compiler can do:
ClassName object = otherObject;
It can pass by value.
// white.h:
class IWidget {
public:
virtual void set(int) = 0;
virtual int get() const = 0;
};
// black.h:
class WidgetImpl : public IWidget {
public:
virtual void set(int i) override { x = i; }
virtual int get() const { return x; }
private:
int x;
};
// white.h:
class white Widget {
public:
void set(int i) { setInternal(i); }
int get() const { return getInternal(); }
};
// black.h:
class black Widget {
private:
void setInternal(int i) { x = i; }
int getInternal() const { return getInternal2(); }
private:
int getInternal2() const { return getInternal3(); }
int getInternal3() const { return x; }
private:
int x;
};
// foo.cpp:
#include "white.h"
void foo() {
Widget w;
w.set(2);
std::cout << w.get() << endl;
}
> I think that is possible to benchmark 90% of this functionality today. Only
> thing we lack is `sizeof` but this can be work around by using
> `std::aligned_storage` that have size margin (you should be able add couple
> of new members before you run out of space in it).
sorry, how did you calculate this 90%? And bench marking what exactly?
The design is not yet even ready, we do not know what needs to be
changed in the compilers and linkers. Benchmarking which build? Can
you please make more clear statements?
> Another thing is that on C++ VLA committee reject runtime `sizeof`, do you
> think they will allow it in your proposal?
Did they reject in the past? Do they always reject? You assume they
are going to reject? Can you also pls. be more clear here?
> Even if we allow it you still
> can't add members of that type to another class. Its because every access of
> members declared after it will require function call for correct offset.
Sorry, this one not clear either? You mean function call to get the
offset? If you have the function to get the offset, why would it be a
problem. You are contradicting yourself in the same statement. Another
option to offset function is the link time inlining. Please read
through the thread, you may have some of the questions clarified.
class black A1 { void foo(); };
class black A2 { void foo(); };
class B
{
int i;
A1 a1;
int c;
A2 a2;
int d;
};
int main()
{
B b;
b.c = 5; //require function call to get offset value.
b.d = 3; //2x call for A1 and A2
b.a2.foo();
temp<&B::d> something; //error, this require runtime values.
int i = sizeof(b); //runtime value too
}
> I think it would be better if we require that "black" declare max size of
> "white" part. This will made it a lot of easer to implement (e.g. it will be
> possible to do today with lot of boilerplate) and pass committee.
Max size is out of question. It is hack, I would personally downwoat
sthg. like that. How would you decide on max size? You will have 300
hundred classes and you will spend 30% of effort in adjusting the max
sizes? That would work in o toy application, but not on giant
projects. Would you just waste memory because design is bad and memory
is cheap?
>> sorry, how did you calculate this 90%? And bench marking what exactly?
>> The design is not yet even ready, we do not know what needs to be
>> changed in the compilers and linkers. Benchmarking which build? Can
>> you please make more clear statements?
>>
> This is approximation, meaning of this was that is possible to recreate most
> of this using current tools, but without any syntax support.
Still not clear what you want to measure. Even if it would be already
implemented you would have hard time to measure. You measure what
against what? Build times would be clearly 1000 times faster if you do
not have to recompile 1000 object files with same complexity each time
you change the definition of a class they are depending on. The same
time you can have a simple build where this will bring zero added
value, more it will be a little bit slower. About runtime performance
difference: there will be to solutions. link time inlining or "runtime
sizeof". The first will be a bit slower to build, the second will be
slower to run. How much slower? dependends on the situation. If you
have 50 times access to the same member inside one function the
compiler is supposed to cache the offset. So the degradation will not
be probaly that significant, but again will depend on the situation.
If getters/setters will be inlined by the linker, I expect almost zero
degradation.
Please define what and how you want to measure.
>> > Another thing is that on C++ VLA committee reject runtime `sizeof`, do
>> > you
>> > think they will allow it in your proposal?
>>
>> Did they reject in the past? Do they always reject? You assume they
>> are going to reject? Can you also pls. be more clear here?
>>
> All proposal that didn't have fixed size objects avoided declaring `sizeof`
> for them. e.g.
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3875.pdf
> And I recall some discussion about it, that people form committee didn't
> like it.
> I tired find link to it but right now I dint find it, maybe someone els
> remember this?
Please do not confuse with some proposals that had as object
dynamically growing objects or anything in that direction. In this
proposal the size is not known at compile time, but it will not change
at runtime. The proposal however keeps it open dynamically loaded
classes and in that case offset and size have to be dynamic.
On 2015–02–27, at 6:31 AM, mobi phil <mo...@mobiphil.com> wrote:May I kindly ask you to go through all emails. This problem was
already addressed. The proposal does not intend to replace all the
usage of all the classes in all the templates in all the world. There
are classes that do not provide other kind of protocols that make them
unusable in thousands of other templates. The proposal will not
satisfy the interface for sizeof at compiltime and with that this part
of topic is closed.
On 2015–02–27, at 7:44 AM, David Krauss <pot...@gmail.com> wrote:By the way, the VLA/“classes of runtime size” proposal did not provide for varying object size at runtime, to my knowledge.