Helping with __mutable (which will be renamed to __metadata)
Doc Andrew
x at x.com
Mon Apr 15 13:32:51 UTC 2019
On Monday, 15 April 2019 at 11:09:23 UTC, Timon Gehr wrote:
>>
>> A few questions/thoughts (or at least food for thought for
>> others more informed than me):
>>
>> 1. Maybe it's just me, but why the leading underscores? I'm
>> wondering if this is because it's a scary/ugly-on-purpose
>> feature like __gshared that is intended only sparingly?
>> ...
>
> Yes. Also, it means we don't reserve a previously unreserved
> identifier.
>
>> 1b. A lot of people have been clamoring for immutable by
>> default, might keeping the DIP's original annotation "mutable"
>> (with no underscores) make this a step in that direction?
>> (with all the baggage and argument that carries with it, which
>> is out of scope for this discussion).
>> ...
>
> It's not the same.
Oh no, I'm just suggesting that, under the original proposed DIP,
the __mutable keyword might as well be made "mutable", which may
be useful later on for other purposes. The metadata concept could
be a lot more powerful, though, and I think it's basically
orthogonal to the mutability concern:
>>
>> 2. If the __metadata qualifier can only be applied to private
>> fields, and carries special semantics w.r.t. escaping the type
>> system, is there any benefit to treating it more like a
>> visibility attribute?
>>
>> struct something
>> {
>> metadata // maybe type qualifiers disallowed in
>> here
>> {
>> int a;
>> }
>> private
>> {
>> int b;
>> }
>> public
>> {
>> int c;
>> }
>> }
>> ...
>
> Is your suggestion just to make __metadata imply private, or is
> there anything else you are trying to say?
Not just private, but it would be a way to annotate data that
lives "outside" of the POD of the class. For instance,
serializing an object with variables in the metadata{} block
wouldn't (or couldn't?) include them.
Another idea I had this morning is that the metadata{} block
might be a nice place to put class/function attributes to avoid
cluttering the signatures:
class Foo
{
metadata
{
synchronized; // can move class attributes in here
scope;
@(someUDA); // UDA's live here too
int secretSauce; // Can always be accessed or modified
by Foo, regardless of
// mutability
}
}
The concept fits nicely with contracts and functions, too. Just
as metadata{} blocks in a immutable object allow modification of
those member variables, maybe member variables in a function
metadata{} block can be modified and persisted across calls for
pure functions, too. It would act just like a static variable,
available at both compile-time and run-time, maybe useful for
things like debugging, profiling or benchmarking. Maybe code in
the in & out contract blocks can access it, but we'd make it
illegal for the function body to do it. I'd need to think through
the side-effects a little more.
int Bar(int a, int b)
metadata
{
pure: // Not 100% sure what syntax
would make sense
@nogc: // maybe just force @ for
everything here
@safe:
long startTicks; // Stuff for benchmarking
long endTicks; // Not pertinent to the function
itself
static int numTimesCalled; // This is a pure function...
}
in
{
numTimesCalled++; // ...but it's OK, we're just
modifying it's metadata
...
}
do
{
if(numTimesCalled > 4) // Illegal to do this here,
breaks purity
...
}
>
>> And... maybe metadata shouldn't be stored with the object at
>> all? This way, it doesn't affect the layout of the object in
>> memory, and doesn't require the need to short-circuit the type
>> system if a later use of the class is marked Immutable. The
>> object's metadata lives, not sorta-outside the type system,
>> but outside the object itself? There are some challenges I can
>> think of with this approach that I can expand on, but also
>> some benefits.
>>
>> -Doc
>
> Storing the data within the object is the point. As the
> original post states, the motivation for the DIP is to allow
> memory allocation schemes such as reference counting, as well
> as lazy initialization to be implemented for
> `immutable`-qualified data structures. The mutability is
> supposed to be an implementation detail -- from the outside,
> the data will still appear to be `immutable`. (The current
> version of the DIP completely misses this point though, leaking
> __metadata into the type system.) Compiler optimizations can
> change the semantics of code that operates on __metadata.
> (e.g., if it is able to elide a read to a lazily-initialized
> field, that field will not be initialized, if it elides a
> reference copy, the reference count does not need to be
> updated, etc.) Therefore, modifications of __metadata need to
> be consistent with rewrites that are valid for strongly pure
> functions.
Sure, I'm just suggesting that keeping that reference count or
other metadata separately is a possible workaround - as long as
there's an easy way to get the metadata for a given object
(whether in memory alongside the rest of the object's data or
not).
The idea of storing metadata member variables separately is an
implementation detail. To the class, it appears that the metadata
members are no different than regular variables, but casting to
void* or serializing it leaves out the metadata, so it's a safe
place to keep things like reference counts. In this scheme,
metadata can be added to classes or structs without changing
their memory layout, and metadata vars have some other special
powers as far as being treated differently by the type system,
strictly because they are stored "outside" the object memory, not
because of a special-case in the type system.
-Doc
More information about the Digitalmars-d
mailing list