An Issue I Wish To Raise Awareness On

Marco Leise via Digitalmars-d digitalmars-d at puremagic.com
Tue Jul 25 12:22:11 PDT 2017


Am Thu, 20 Jul 2017 08:56:57 +0000
schrieb Kagamin <spam at here.lot>:

> On Wednesday, 19 July 2017 at 12:56:38 UTC, Marco Leise wrote:
> > That's exactly what I was opposing in the other post. These
> > handles are opaque and never change their value. Within the
> > Dlang language barrier they can be immutable and as such,
> > implicitly shared.  
> 
> Given transitivity of immutability the handle should have the 
> same immutability as the resource it represents.

I understand that you apply D keywords to C types in a
best fit fashion, to get some errors from the compiler when
you use them in the wrong context. It should work alright in
some APIs (maybe you can show me an example).

But since C does not have these qualifiers, one function may
be used for shared and unshared resources or the library may
even be compiled with or without thread-safety enabled and you
have to query that at *runtime*, where you have no help from
the type-system. So I believe, relying on the pattern will be
frustrating at times as not general enough.

What I seek to achieve by slapping immutable on things like
file descriptors and opaque types is the use as hash table
keys. As the hashed part of hash table keys must not change,
this approach enables us to use these types as keys and
statically verify immutability, too.

Because opaque structs and integer handles are used in C
APIs to *hide* the implementation details, the compiler is
deliberately left blind. That FILE* could as well be an
integer as far as transitivity of `immutable` goes. Nothing
the compiler *can see of it* will ever change. And that's all
the type system will ever care about really! Even if part of
that hidden structure is actually returned mutably by some
function, it is just an implementation detail. Whether you
slap `immutable` on anything there is mostly cosmetic.

Now what does that mean for type checks in practice?

1) Looking at POSIX' C `fgetc()` function, the stream is a
   plain FILE*: int fgetc (FILE *stream).
   Since I/O is thread-safe[1], it should ideally be `shared`
   the way you put it. And the way I look at it, it should be
   `immutable` on *our* side of the language barrier. (I.e.
   Dlang wont be able to change its contents or see the
   contents change.)

2) You can look up items by file descriptors or FILE* in hash
   tables implementations with immutable keys.

So we can take this away:
* Making a struct opaque, is implicitly making it immutable,
  because it's contents cannot be modified nor read directly - 
  the compiler cannot reason about its contents.
* Now we also have a layman's head-const, making resource
  pointers usable as immutable hash table keys.

As you can see my thinking revolves around the idea that hash
table keys must be immutable and that stems from the idea that
once hashed and sorted into a table, the hashed data must not
change. There are other approaches and druntime's AAs simply
allow mutable keys:

	void main() {
		struct S { int* i; }
		int a = 1, b = 2;
		uint[S] aa;
		aa[S(&a)] = 42;
		foreach(ref s_key; aa.byKey())
			// Allows "innocent" changes to the keys
			s_key.i = &b;
		foreach(ref s_key; aa.byKey())
			// AA doesn't find the key it just returned! Range violation.
			uint u = aa[s_key];
	}

-- 
Marco



More information about the Digitalmars-d mailing list