Property discussion wrap-up

Timon Gehr timon.gehr at gmx.ch
Tue Jan 29 05:29:23 PST 2013


On 01/29/2013 01:02 PM, Artur Skawina wrote:
> On 01/28/13 23:17, Timon Gehr wrote:
>> On 01/28/2013 01:34 AM, Artur Skawina wrote:
>>> On 01/28/13 00:23, Timon Gehr wrote:
>>>> On 01/27/2013 07:12 PM, Artur Skawina wrote:
>>>>> ...
>>>>> While it's true that "counter-example" is not the best way to describe the issue,
>>>>> it /is/ something that is worth considering. And I say that as somebody who was
>>>>> (and still is) arguing for keeping the last pair of (),
>>>>
>>>> You can do that in any case.
>>>>
>>>>> because they carry important info for the person /reading/ the code,
>>>>
>>>> Often that is not the case.
>>>
>>> Hmm, let's try an example.
>>> Imagine a project, which defines a set of reasonable policies, such as:
>>>
>>> Properties may not:
>>>    - allocate memory
>>>    - grab locks
>>>    - block
>>>    - throw exceptions
>>>    - cause unexpected changes to the program flow (eg no thread ops)
>>>    - etc
>>>
>>> Now you only need to make sure that these are followed, either via reviews
>>> and audits, or some checking tool. But once you're reasonably sure that this
>>> is done, you can reason about code, without having to either know or check
>>> absolutely everything - which simply does not scale.
>>
>> As long as there is no actual proof, you still need to take all those cases into account.
>
> A proof is always nice to have, therefore the mention of "some checking tool".
> However even in the absence of one, you get the benefit of being able to split
> the problem into smaller ones. First check that the above policies for
> @properties are followed, which should be a much smaller task, and one that
> can be done incrementally (reviewing new code). Then use that information when
> reading /all/ of the code (including the @property implementations).
>
>> If you think otherwise, I do not see why you believe that anyone on such a project would leave off the parens when they should not be in order to make the above conventions visible at the call site.
>
> If it would be possible to completely trust every programmer to follow
> conventions  then we wouldn't need eg "const". Because nobody would modify
> an object when they're not supposed to, right? Now imagine a scenario
> where 'const' does exist but is optional, ie not enforced by the compiler.
>

I do not see any consistent line of reasoning that I could agree with or 
argue against in the above paragraphs. I think the reasoning is 
contradictory, because it argues for opposite cases in analogous setups. 
What am I missing?


>
>>> So a block like
>>>
>>>      {
>>>          auto lock = grab.some.lock();
>>>          if (a && b && c.d)
>>>             e = f;
>>>      }
>>>
>>> is then safe from certain class of bugs.
>>>
>>
>> Not yet. You missed the potential memory allocation, lock, blocking operation, thrown exception and thread op in e's opAssign.
>

I forgot about the side-effects of the ~500 alias this lookups in that 
example. :o)

> No, I just assumed that sane op overloading policies were given, in this
> case similar to the @property restrictions.

I see. The post explicitly stated that @property policies would be 
sufficient though. Anyway, I guess extending on the points made, the 
only sane op overloading policy is to not use op overloading, because 
not using it means you gain the information that every operator is a 
built-in?

> But it's not about catching
> every single potential bug, it's about making the common cases safe. You
> do need /some/ context information when reading code; it's requiring that
> you either know or check every possibility that does not scale.
>
> Even if "assignments to typeof(e) may allocate, block and throw" is true,
> it just means there's one more thing to be aware of, but does not reduce
> the value of being able to reason about the other accesses.
>

If the ultimate goal is to _reason_ about code more easily, using only 
safe pure functions and/or writing down actual machine-checkable 
specifications and/or using static analysis tools that actually prove 
the absence of certain classes of issues is a much better way to go 
about it. () or not () just does not enable very powerful statements 
about the code. (Most code snippets will actually contain a () call.)

> ...
>> And another one about identifier naming. 'a', 'b', 'c', 'c.d', 'e', 'f'?
>
> If you have to resort to explicitly encoding unnecessary information in
> identifiers then something is wrong.

I have no idea how that differs from "If you have to resort to 
explicitly encoding unnecessary information in '()' then something is 
wrong."

> Having a naming convention is ok,
> but having it say "methods must end in Method,  to avoid confusion with
> plain data and properties" is not.
>

So information beyond 'a', 'b', 'c', 'c.d', 'e', 'f' is unnecessary, but 
a trailing '()' is extremely important?

>
>>> Yes, the "proper" way to handle this is using attributes,
>>
>> Yes.
>>
>>> but that is not possible now, nor will it be in the near future.
>>
>> Well, you already bring forward the possibility of having a checking tool.
>
> Proper attributes are way out of scope of this discussion. I do think
> they can be done relatively cleanly in a D-like language (via aot udas
> and ctfe), but for now @properties are here and would be much more
> useful if ()-less calls weren't.
>

We disagree here. (It's not that I don't get what you are saying, it is 
just that this is not important at all in some projects, and therefore 
it imo makes no sense to hard-wire it into the language.)

> A checking tool should only be necessary for things that the compiler
> can't handle itself, mostly expensive checks that can't be run at
> compile time.
>

The checking tool should be built using a compiler API and run alongside 
normal compilation.

>>> OTOH @properties
>>> are already available and in combination with enforcing () on all
>>> other calls can often be used in their place.
>>>
>>
>> And there are quite a few other ways to achieve the same thing.
>
> Like?
>
>>> Allow parens-less calls, and suddenly the value of having @property
>>> drops significantly, almost to the point that they can be eliminated.
>>
>> Your policies can still be applied, if you like.
>
> With a tool that checks the source for ()-less calls.

So () needs automated checking but not the part about allocations, 
locks, thread ops, etc, for which code reviews are sufficient?

> No, this is not a good solution.
>

What else are you arguing for the entire time?
Furthermore, the ()-checking tool already exists as part of DMD!

>>> This is why the optional-parens debate is /directly/ related to
>>> @properties.
>>>
>>
>> As far as I am concerned, @properties are mostly sugar most of which is not implemented yet.
>
> Of course. But they would be useful when implemented. The ()-less
> calls are the main problem, both when evaluating a property (which
> returns a callable)

No problem there.

> ...
>>
>> They obviously go hand in hand. But "reasoning" about code that refers to definitions one is not aware of any specifications of is just rambling anyway.
>
> Umm, a policy, such as the one in my example, *is* a spec.

Yes, it is a (quite weak) spec.

> The alternative is to be aware of the complete implementation,

'The' alternative to what exactly?

> which does not scale beyond small and self-contained programs.
>
>> ...
>>> syntax is something one can get used to, lost information is gone.
>>>
>>
>> No information is lost. It's you who defined that any information is carried at the call site.
>
> Allowing 'a' to act as 'a()' means that the reader no longer can tell
> that 'a' isn't a function call (or was /specifically designed/ to be
> used like this).
>

But that is obviously because it is called 'a'!

Make it 'x.map!(a=>2*a)'. No more issues.




More information about the Digitalmars-d mailing list