Saturday, December 12, 2015

Digest for comp.lang.c++@googlegroups.com - 11 updates in 4 topics

Daniel <danielaparker@gmail.com>: Dec 12 09:09AM -0800

I'm trying to understand the rules for alignment with placement new.
 
If we have
 
struct A
{
size_t length;
};
 
my understanding (please correct me if I'm wrong) is that this results in a
data structure that is properly aligned:
 
typedef typename std::aligned_storage<sizeof(A),
alignof(A)>::type storage_type;
 
char* storage = new char [sizeof(storage_type)];
A* pa = new(storage)A();
 
But what if we have
 
struct B
{
size_t length;
int *p;
};
 
and wish to allocate storage for B and p with placement new from the same storage?
 
Does this satisfy alignment rules?
 
typedef typename std::aligned_storage<sizeof(B),
alignof(B)>::type storage_type;
 
size_t length = 10;
char* storage = new char [sizeof(storage_type)+length*sizeof(int)];
B* pb = new(storage)B();
 
pb->p = new(storage + sizeof(storage_type))int[length];
 
Thanks,
Daniel
"Öö Tiib" <ootiib@hot.ee>: Dec 11 06:01PM -0800

On Saturday, 12 December 2015 01:13:29 UTC+2, Chris Vine wrote:
 
> Static polymorphism requires you to propagate types. That is not what
> is normally intended with dependency injection. But no one owns the
> expression so it can mean whatever you want it to mean.
 
I thought what was intended with dependency injection was to depend on
abstractions (loose coupling) not to depend on concrete types (tight
coupling). So if statically passed type conforms to needed abstraction
(or concept) then what was intended has been achieved. It is even better
for programmer if nothing was needed to be passed since statically
defaulted type does already what is needed.
 
> > policies. The .NET gang typically injects interface pointers.
 
> Which is what is normally meant by dependency injection (or the C++ or
> Java or ... equivalent).
 
Abstract interface and dynamically polymorphic pointers are one way
to achieve abstraction. In C++ we never limit ourselves to single way
because we want our programs to work as simple way as possible and
ourselves to express it as simple way as possible. However never simpler
than possible so sometimes we also need dynamic polymorphism in C++ too.
 
> all the time. They are perhaps closer to the command pattern but all
> these (strategy pattern, command pattern, policy pattern, dependency
> injection) are related and serve similar ends.
 
Principles are important. There are no silver bullet "normal" techniques
to follow those principles. Most important principle is KISS. Lot of
dynamically polymorphic interfaces can cause explosion of types,
complexity shifting into relations between classes and that may
cause difficulties to trace behaviors. Result may easily become hard
to handle without tools that the OP asked for or even with those. ;)
"Tobias Müller" <troplin@bluewin.ch>: Dec 12 07:55AM

>> I see no big difference except the increased verbosity of templates.
 
> Resulting in the template keyword spreading like a virus in your code
> with a proportional increase in compilation time and binary file size.
 
If you want static polymorphism everywhere then yes, that's the price to
pay.
Compilation will increase for sure, binary size depends. In practice you
probably won't have too many different instantiations and with better
optimization possibilities size could probably even decrease.
 
> The big difference is having dependencies on abstractions rather than
> concretions results in looser coupling and better design sausages.
 
Nothing prevents you from still having an IBar interface. Bar beeing a
template itself is orthogonal to that.
I'm not saying that runtime polymorphism is generally bad and templates
should always be preferred. But if you need the performance it's a valid
alternative for achieving DI.
 
Tobi
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 12 10:58AM

On Fri, 11 Dec 2015 18:01:44 -0800 (PST)
> (or concept) then what was intended has been achieved. It is even
> better for programmer if nothing was needed to be passed since
> statically defaulted type does already what is needed.
 
I think we are in danger of talking across each other and losing the
point, whilst agreeing. It's purpose is loose coupling by externalizing
or delegating the required behaviour to the injector (aka dependency
inversion). The service object supplying the dependency will of
necessity be concrete, but will be owned by the client polymorphically
in some fashion (it does not know or care how its dependency is
implemented). This might involve the service object being passed as an
interface/ABC, but that is an implementation detail; it could equally
well be held by a polymorphic function object in the signal/slot
style. I don't think either of us disagree with that.
 
Furthermore static polymorphism requires you to propagate the
polymorphic behaviour via types. I don't think either of us disagree
with that either. That causes a multiplication of types and therefore
of templates.
 
In its purest form DI does not provide defaults: the user is expected
to provide the service objects on configuration. But if you want a
default, that is orthogonal to whether you use static or dynamic
polymorphism.
 
None of this is particularly new. We have been doing it for years. As
someone else has mentioned, what is new(ish) is the availability of
frameworks to manage the explosion of dependency complexity the
technique can cause.
 
Chris
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Dec 12 03:40PM

On 12/12/2015 07:55, Tobias Müller wrote:
> I'm not saying that runtime polymorphism is generally bad and templates
> should always be preferred. But if you need the performance it's a valid
> alternative for achieving DI.
 
It isn't proper DI though as it involves dependencies on concretions
rather than on abstractions sausages.
 
/Flibble
"Tobias Müller" <troplin@bluewin.ch>: Dec 12 04:03PM

>> alternative for achieving DI.
 
> It isn't proper DI though as it involves dependencies on concretions
> rather than on abstractions sausages.
 
I think I've lost you. I don't see any concretions.
 
Tobi
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Dec 12 04:37PM

On 12/12/2015 16:03, Tobias Müller wrote:
 
>> It isn't proper DI though as it involves dependencies on concretions
>> rather than on abstractions sausages.
 
> I think I've lost you. I don't see any concretions.
 
The template parameters are concrete rather than abstract types sausages.
 
/Flibble
"Öö Tiib" <ootiib@hot.ee>: Dec 12 08:49AM -0800

On Saturday, 12 December 2015 12:58:27 UTC+2, Chris Vine wrote:
> > statically defaulted type does already what is needed.
 
> I think we are in danger of talking across each other and losing the
> point, whilst agreeing.
 
That is possibility.
 
> interface/ABC, but that is an implementation detail; it could equally
> well be held by a polymorphic function object in the signal/slot
> style. I don't think either of us disagree with that.
 
Yes. There is at least one more style of dynamic polymorphism (a "variant").
It is quite widely used for compacting data but not for inverting
dependencies.
 
> polymorphic behaviour via types. I don't think either of us disagree
> with that either. That causes a multiplication of types and therefore
> of templates.
 
How it causes multiplication of templates? What is bad about templates?
For me templates cause relations that are already known compile
time to be fixed. For programmer it is way to "favor immutability"
for compiler it is opportunity to diagnose issues early and to optimize.
Introducing dynamic polymorphism where unneeded is worse than avioiding
'const' keyword.
 
> to provide the service objects on configuration. But if you want a
> default, that is orthogonal to whether you use static or dynamic
> polymorphism.
 
The issue of defaults is orthogonal in theory but actual in practice.
The difference is that dynamically polymorphic defaults must be ready
made and available even when not used by particular module. That
means run-time paying for something that is not used. Unless such
default is something extremely cheap and trivial it is not made.
 
> someone else has mentioned, what is new(ish) is the availability of
> frameworks to manage the explosion of dependency complexity the
> technique can cause.
 
Right. Doing that in correct way for C++ by taking into account what
objects or relations are immutable and what are not is slightly more
difficult than in languages where everything is pointer to object whose
every method is virtual. However the outcome will keep beating
others 4:1 and after all ... that is all that matters. ;)
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Dec 12 03:23PM +0100

On 12/10/2015 2:49 PM, Alf P. Steinbach wrote:
>[snip]
 
This header has now evolved a little.
 
• Due to David Brown's commentary I realized that the "wrap_to" function
did not do anything that proper suppression of sillywarnings didn't do,
so, removed -- it was not a proper way to suppress that sillywarning
(I wonder about the process in Microsoft that causes them to introduce
ever more and ever more misleading sillywarnings for Visual C++, hmf).
 
• For consistency and for more expressive readable code, and to mirror
the template meta-programming boolean operations (hm, it would be nice
with OPERATORS for types!), I added functions "exactly_one_of" (xor),
"all_of" (and), "not_all_of" (nand), "any_of" (or) and "none_of" (nor).
 
• With improved template "Type_set_" I could simplify the type set
expressions. Interesting tidbit: just small typos in the code for
"Type_set_" caused Visual C++ to near-crash, unable to recover from the
errors, and telling me that I would be asked to report this to
Microsoft. Not an ICE, but evidently not-by-design behavior. That's
apparently new with Visual C++ 2015. Never seen it before, and I've
reported a host of internal compiler errors for Visual C++.
 
<code>
#pragma once
// core_language_support/basic_types.hpp
// Copyright © Alf P. Steinbach 2015. Boost Software License 1.0.
 
#include <p/cppx/core_language_support/type_builders.hpp> //
cppx::Ref_
#include <p/cppx/core_language_support/basic_type_aliases.hpp> //
cppx::(Byte, Size)
#include <p/cppx/tmp/Type_set_.hpp> //
cppx::Type_set_
#include <p/cppx/tmp/sfinae.hpp> // cppx::If_
#include <p/cppx/macros/platform_sniffing.hpp> //
CPPX_PLATFORM*
#include <p/cppx/macros/CPPX_STATIC_ASSERT.hpp> //
CPPX_STATIC_ASSERT
 
#include <type_traits> // std::conditional_t
 
// For a discussion of Syschar see the article "Portable String Literals
in C++" by
// Alf P. Steinbach, ACCU Overload journal August 2013; the article is
available online
// at <url: http://accu.org/index.php/journals/1842>. Eessentially it's
the natural
// Unicode character endcoding unit for the system at hand, strictly
typed as an enum.
// As an enum it's compatible with std::basic_string short buffer
optimization.
 
#ifndef CPPX_SYSCHAR_BITSIZE
# if defined( CPPX_PLATFORM_IS_WINDOWS )
# define CPPX_SYSCHAR_BITSIZE 16 // Implies UTF-16
encoding & wchar_t.
# elif defined( CPPX_PLATFORM_IS_UNIXLAND )
# define CPPX_SYSCHAR_BITSIZE 8 // Implies UTF-8
encoding & char.
# else
# define CPPX_SYSCHAR_BITSIZE 0 // Will use wchar_t as a
default.
# endif

No comments: