September 23, 2014
On Tuesday, 23 September 2014 at 10:29:25 UTC, Steven Schveighoffer wrote:
> On 9/23/14 6:26 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
>> Ok, I take it back ;-) Steven is right. It is however the case that this
>> function's return value would still be unique.
>
> Yes, it could be unique. I haven't read this thread really, so I don't know what has been proposed, but looking at the snippet, wouldn't you have to tag the return value? You tagged the parameter with unique.

Bearophile did, not me. But yes, you would have to, absent an extension to return type inference. As I already replied to him, uniqueness was really just used in an example because it made it cleaner; it's mostly unrelated to my proposal.
September 23, 2014
Steven Schveighoffer:

>> int[] foo(unique int[] a) pure {
> ...
> I don't think so. Strong pure function optimizations would not work for something like:
>
> auto x = foo(a) ~ foo(a);

This is similar to:

unique x1 = foo(a);
unique x2 = foo(a);
unique x = x1 ~ x2;

When the call to the first foo ends you have a x1 reference to the array data. Such reference x1 is unique, so now 'a' is not usable any more, you can't pass 'a' to foo once more.
I need to learn more about such stuff of linear typing.

Bye,
bearophile
September 23, 2014
On 23 September 2014 19:45, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 9/22/2014 4:20 AM, Manu via Digitalmars-d wrote:
>>
>> On 22 September 2014 13:19, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com <mailto:digitalmars-d@puremagic.com>> wrote:
>>
>>     On 9/21/2014 4:27 AM, Manu via Digitalmars-d wrote:
>>
>>         It's also extremely hard to unittest; explodes the number of static if paths
>>         exponentially. I'm constantly finding bugs appear a year after writing
>>         some code
>>         because I missed some static branch paths when originally authoring.
>>
>>
>>     If you throw -cov while running unittests, it'll give you a report on which
>>     code was executed and which wasn't. Very simple and useful.
>>
>>
>> It is a useful tool, but you can see how going to great lengths to write this explosion of paths is a massive pain in the first place, let alone additional overhead to comprehensively test that it works... it should never have been a problem to start with.
>
>
> There are two separate issues here - the first is knowing whether or not the code is unittested. -cov solves that issue. The second is having the multiple code paths in the first place.
>
> Have you tried auto ref?

auto ref has never been what I've wanted. Semantically, it makes ref
out of all value-type lvalues, including int/float.
I don't want the compiler attempting to presume what I want in my
generic code. If it's part of the type, then there are no surprises;
it is exactly what I give it, which I gave deliberately.


> I don't really know what the code you show is supposed to do from a high level. My first impression is you are trying to write it like you'd write C++ code. Perhaps there's a more D idiomatic way of doing it that doesn't lead to the tangle you've got.

The only way I can think to eliminate that is to write the lot in a huge mixin which composes the text from bits. I avoid mixin.

D has extensive language to manipulate and compare types, it has very
little to deal with these few weird external concepts like 'storage
class'. D has the most powerful type system I'm aware of, I see no
reason to break from that.
I think 'storage class' is a source of extreme complexity in D, since
it breaks uniformity with the rest of the language.


> BTW, ref (as you know) is part of the type in C++. However, I can vouch for it being a special case everywhere in C++, and is a horrifying quagmire of strange edge cases. That's why it's not part of the type in D.

I've never had any problems with ref in C++. D presents the horrible
quagmire of edge cases in my experience, some of which I've presented,
but I've had many more issues in the past.
Can you give me some examples of the problems in C++ you set out to
avoid? I've been programming C++ for 20 years, and D for 5-6 years.
I've never had this problem in C++, I have it so often in D, it drives
me crazy.

I also believe that D wouldn't suffer the same problems as C++, because we have much better type manipulation. Things like PointerTarget!T, Unqual!T, and all the other complex type manipulation templates are common and work well in D, but that sort of thing almost never works well in C++. The type comparison logic in C++ is too feeble to be comparably useful.
September 23, 2014
On 23 September 2014 19:48, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> Manu, once again your posts have the message embedded twice in them, making for very large posts. What's happening is the posts have the text in plain text, then the text again in HTML.
>
> Please configure your news editor to only produce the plain text messages. The HTML versions are ignored and uselessly consume bandwidth and disk space.

I use Gmail. It was configured... but it seems that it reverts to html mode whenever I attach an image in any email I write, and then it remembers the setting :/
September 23, 2014
On 23 September 2014 20:23, via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Tuesday, 23 September 2014 at 09:46:17 UTC, Walter Bright wrote:
>>
>> Have you tried auto ref?
>
>
> For some purposes, auto ref does the wrong thing. Whether you get a reference depends on whether you pass an lvalue or an rvalue. But some templates need to take either a struct by reference, or a class/interface (already being a reference) by value.
>
> This is the case deadalnix mentioned further up in this thread. I don't know whether it applies to Manu's code, too. AFAIUI he's more concerned about forwarding parameters in wrapper types.

That's just in this case. I'm concerned with many different cases over time. This is a half decade running agony for me ;)
September 23, 2014
On 9/23/14 7:11 AM, bearophile wrote:
> Steven Schveighoffer:
>
>>> int[] foo(unique int[] a) pure {
>> ...
>> I don't think so. Strong pure function optimizations would not work
>> for something like:
>>
>> auto x = foo(a) ~ foo(a);
>
> This is similar to:
>
> unique x1 = foo(a);
> unique x2 = foo(a);
> unique x = x1 ~ x2;
>
> When the call to the first foo ends you have a x1 reference to the array
> data. Such reference x1 is unique, so now 'a' is not usable any more,
> you can't pass 'a' to foo once more.
> I need to learn more about such stuff of linear typing.

This begs the question, what is the point of having "strong purity" if you can't optimize based on it?

-Steve
September 23, 2014
On 23 September 2014 21:02, via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Monday, 22 September 2014 at 15:54:23 UTC, Manu via Digitalmars-d wrote:
>>
>> We arrive at yet another case of "it should have been that way from the
>> start" wrt 'scope'.
>> The baggage of annotation, and the lack of annotation to existing code is
>> a
>> pretty big pill to swallow.
>> If it were just part of the type, there would be no problem, T would
>> already be 'scope T' in the cases where you expect. I can't see any
>> disadvantages there.
>
>
> But it has very different semantics. You cannot expect the same code to work for scope and non-scope alike. And it is to be expected  that you have to adjust existing code if you want to take advantage of a new feature. If by "it should have been that way from the start" you mean that scope should be the default, well yes, but we're in the same situation with immutable by default, pure by default, @safe by default, nothrow by default, ... That ship has sailed, unfortunately.

You can't expect the same code to work for int and immutable(int)
alike either... or int and int[], they all have to be handled somewhat
explicitly.
Generic code shouldn't try to work with is(T == scope(U), U) if the
code doesn't support scope. If the generic code is to support scope,
then the generic code either specifies it's argument to be scope(T),
which works the same as const(T) wrt mutability, or it detects and
handles is(T == scope(U), U) internally.

And yes, that's what I meant by 'should have been that way from the start' :)


>> This would be another band-aid to a core problem. D already has plenty of
>> these.
>> I hear this "perfect forwarding" concept thrown around, and I think it's
>> another faulty concept. I rarely want 'perfect' forwarding... why would I
>> be forwarding in the first place if it's 'perfect' (there are cases, but
>> not so common)? I almost always want *imperfect* forwarding; that is, some
>> small detail(/s) about the forwarding are manipulated. I think this is the
>> primary case where storage class falls apart in concept.
>
>
> That is a straw man. Of course, perfect forwarding needs to allow for imperfect forwarding, too. It would indeed be not useful if you couldn't inspect and modify the types (and storage classes) of your parameters.

Well you suggested like perfect forwarding was a discrete problem to solve.
Imperfect forwarding implies composing a signature from a complex set
of typeof(), alias, template arguments, traits, etc. We can't be
losing ref-ness in any of these cases, or the forwarding is broken.
scope likewise.
(im)perfect forwarding would work just fine right now if there wasn't
random bits of information that were separated from the type system.


>> Maybe you can give counter examples too, if you think it doesn't work.
>>>
>>>
>>
>> It's complex and time consuming to do so. The situations where it all
>> breaks down are often fairly complex (probably why 'ref' as a storage
>> class
>> seems like an okay idea at face value, although I still don't understand
>> the advantage conceptually), and they tend to appear when you don't expect
>> it. My examples with ref above are all practically applicable to scope too
>> though.
>
>
> A concrete example would still be very helpful to understand your point of view. I.e., not only the concrete wrapper type/function, but also how you would want to use it, and why it wouldn't work without scope being part of the type.

Generating function signatures is certainly the simplest and also the
most common example of these problems.
The problem is simple; if it's not part of the type, then the only
solution is a static if with explicit detection for the thing, and
code duplication with/without the non-type attribute.
Templates are rarely flat either, they are usually a composition of
other templates. Everything in the chain needs to have special case
handling for ref (and scope) that lives outside the type system.

>> Let's turn this around... Why the complexity? Why would you make the
>> change
>> to your proposal to make 'scope' something else outside of the type
>> system?
>
>
> Well, I think Ivan gave an excellent example (ElementType) why it should be separate from the type. Type modifiers currently only deal with mutability (and the related shared). There can be some nasty surprises if we add another concept there.

I don't think shared is really related, also what about *, [], [n],
etc. these are all type modifiers that cause the same sort of
'surprises'.
We have tools for dealing with all of these: Unqual!T,
PointerTarget!T, isPointer!T, isArray!T, etc... they all work well, I
haven't had any complaints about them personally. scope detection
would have no significant impact on the mix.

We also have tools like is(T : U), which should be extended to work as
expected with scope.
In the same way as "is(X : const(T)) == true" works for T == mutable,
immutable, or const, we would have the same is(X : scope(T)) to detect
if the lifetimes are compatible.
We need scope in the type system so we can make use of all the
powerful type manipulation features that D has. As far as I'm
concerned, D's type system *IS* D. (this is also true for ref)


>> What is the advantage to that complexity. D has no structured method for dealing with that sort of meta, we only have types. Beyond that, it's just spaghetti, as we learn from ref.
>
>
> Then it's better to introduce such a method, IMO.

Please no. D does NOT need a parallel suite of syntax to deal with 'storage class' meta.
September 23, 2014
Steven Schveighoffer:

> This begs the question, what is the point of having "strong purity" if you can't optimize based on it?

Linear typing gives some guarantees that help the GC a lot, and avoid some coding mistakes. And some people could answer you that having (strongly) pure functions is a quality regardless of optimizations, because it makes both unit testing and code understanding simpler :-) I am not very expert on this stuff, I need to learn more.

Bye,
bearophile
September 23, 2014
On 9/23/2014 4:21 AM, Manu via Digitalmars-d wrote:
> On 23 September 2014 19:48, Walter Bright via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>> Manu, once again your posts have the message embedded twice in them, making
>> for very large posts. What's happening is the posts have the text in plain
>> text, then the text again in HTML.
>>
>> Please configure your news editor to only produce the plain text messages.
>> The HTML versions are ignored and uselessly consume bandwidth and disk
>> space.
>
> I use Gmail. It was configured... but it seems that it reverts to html
> mode whenever I attach an image in any email I write, and then it
> remembers the setting :/
>

Well, that message was right!
September 23, 2014
On Tuesday, 23 September 2014 at 10:29:25 UTC, Steven
Schveighoffer wrote:
> On 9/23/14 6:26 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
>> Ok, I take it back ;-) Steven is right. It is however the case that this
>> function's return value would still be unique.
>
> Yes, it could be unique. I haven't read this thread really, so I don't know what has been proposed, but looking at the snippet, wouldn't you have to tag the return value? You tagged the parameter with unique.
>
> -Steve

Unique is a bad name. You want to have various reference locally,
and the whole discussion is about scope.

Which bring us to the main point here, before discussing
borrowing, we'd better define ownership.