Skip to content

Conversation

nordlow
Copy link
Contributor

@nordlow nordlow commented Oct 20, 2014

Thanks to @aG0aep6G this works as far as I can see.

@nordlow
Copy link
Contributor Author

nordlow commented Oct 20, 2014

}

@property ref inout(T) back() inout
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if elements are immutable? Then things like arr[].filter(x > 0).array degrade to const element.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Not related to DmitryOlshansky's comment.)

Looks like I've missed an else here. There should be no elses to the static if (isMutable!A)s.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add another

        else static if (is(T == immutable))
        {
            @property ref immutable(T) front() const
            {
                version (assert) if (empty) throw new RangeError();
                return _outer[_a];
            }
            @property ref immutable(T) back() const
            {
                version (assert) if (empty) throw new RangeError();
                return _outer[_b - 1];
            }
        }

then?

@JakobOvrum
Copy link
Contributor

Array.Range is a public type that is used as a parameter type of many of Array's methods, so this is a pretty serious breaking change.

@JakobOvrum
Copy link
Contributor

I don't think adding all this duplicated code is a nice solution to this problem. The fundamental issue is that we have conversions for const(T[]) to const(T)[] but no equivalent way to implement const(Array!T) to Array!(const T) (and ditto for immutable).

@aG0aep6G
Copy link
Contributor

JakobOvrum wrote:

Array.Range is a public type that is used as a parameter type of many of Array's methods, so this is a pretty serious breaking change.

We could get around the breakage by renaming the range template to RangeT or something, and adding an alias Range = Range!T(Array);.

@nordlow
Copy link
Contributor Author

nordlow commented Oct 26, 2014

@aG0aep6G I guess you mean

alias Range(T) = RangeT!(Array!T);

right?

@aG0aep6G
Copy link
Contributor

(...)

I meant alias Range = RangeT!(Array);. Alternatively, alias Range = RangeT!(Array!T) would be equivalent. But no (T) on the left side.

And it has to go into Array, because that's where it's been the whole time.

The point is that Array!Foo.Range has been a concrete type so far, and should stay that way.

@aG0aep6G
Copy link
Contributor

I made a pull request against your branch with what I mean: nordlow#2

@nordlow
Copy link
Contributor Author

nordlow commented Oct 27, 2014

Sigh, I got back the same compilation errors after merging #2643. I don't understand what I did wrong. How do I ignore edits from pull 2643 when I merge or rebase?

@aG0aep6G
Copy link
Contributor

What errors? What do you want to do? What did you do?

@nordlow
Copy link
Contributor Author

nordlow commented Oct 28, 2014

My rebase gave merge conflicts beyond what I could resolve because someone did a revert of previous work on the constness of array.d at #2643. I start over and see what you guys think this time.

@aG0aep6G
Copy link
Contributor

When throwing away everything from #2643, you also deleted this test: https://github.com/Dicebot/phobos/commit/1149972daca5290ed401dcd0a03f3a7eb5c5074c. Better put it back in.

@nordlow
Copy link
Contributor Author

nordlow commented Oct 28, 2014

Done. BTW: Don't we need a specific test for immutable Arrays and/or Ranges?

@aG0aep6G
Copy link
Contributor

I have a suggestion that's rather invasive. So I made a pull request: nordlow#3

The commit message:

T misses A's qualifiers which are needed. E has them. This means,
const/immutable are taken over from A automatically. This allows inout
to be used on front/back/opIndex. inout doesn't work for opSlice, but the
isMutable!A guard can be dropped.

move*, opSliceAssign, etc would be strictly fine with T, but to avoid
confusion I think it's better to not use T in Range at all.

This gets us rid of quite some duplication. Also adds tests for const/immutable Arrays/Ranges.

@MartinNowak
Copy link
Member

I don't think adding all this duplicated code is a nice solution to this problem. The fundamental issue is that we have conversions for const(T[]) to const(T)[] but no equivalent way to implement const(Array!T) to Array!(const T) (and ditto for immutable).

True, but there doesn't seem to be an alternative solution.
What you actually want here is covariance w.r.t. template arguments, e.g. Array!T implicitly converts to Array!(const T).
In Scala you'd write Array[+T] to express that.

@MartinNowak
Copy link
Member

I'd really like to have a solid solution to this problem as it's a recurring problem and resorting to Range, ConstRange and ImmutableRange (const_iterator) is pathetic.
This is the best idiom I could come up with, but it segfaults the compiler (Issue 13667).
http://dpaste.dzfl.pl/70f17b04ee6d
Maybe it's worth to post this on the newsgroup as someone might have a better idea or has already solved the problem.

@nordlow
Copy link
Contributor Author

nordlow commented Nov 2, 2014

Is this or nordlow#3 the way to go forward with this issue? I don't understand why Github says that nordlow#3 is pending. Hasn't this already been merged by me?

@aG0aep6G
Copy link
Contributor

aG0aep6G commented Nov 3, 2014

Everything's here. I'm closing nordlow#3. Maybe you didn't pull it through Github or something.

@nordlow
Copy link
Contributor Author

nordlow commented Nov 3, 2014

Great. Ready to merge?

}

void opSliceAssign(T value)
RangeT!(const(A)) opSlice() const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why these are const instead of using inout?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing to inout triggers a compiler bug and errors as

array.d(235,22): Error: variable std.container.array.Array!int.Array.RangeT!(inout(Array!int)).RangeT._outer_ only parameters or stack based variables can be inout
array.d(235,22): Error: variable std.container.array.Array!int.Array.RangeT!(inout(const(Array!int))).RangeT._outer_ only parameters or stack based variables can be inout
array.d(333,9): Error: template instance std.container.array.Array!int.Array.RangeT!(inout(const(Array!int))) error instantiating
array.d(328,9):        instantiated from here: RangeT!(inout(Array!int))
array.d(386,19):        instantiated from here: RangeT!(Array!int)
array.d(898,5):        instantiated from here: Array!int
array.d(333,9): Error: template instance std.container.array.Array!int.Array.RangeT!(const(Array!int)) error instantiating
array.d(386,19):        instantiated from here: RangeT!(Array!int)
array.d(898,5):        instantiated from here: Array!int
array.d(927,5): Error: static assert  (!true) is false

@JakobOvrum
Copy link
Contributor

All the positional insert and remove methods now only work when given mutable positions (i.e. Array.Range), which may or may not make sense.

Defines the container's primary range, which is a random-access range.
*/
static struct Range
private static struct RangeT(A)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If doesn't depend on T move it out of Array strict.
No need to spread the bloat by putting a template in a template.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe there are different views about this. Do @MartinNowak @Dicebot @yebblies @JakobOvrum agree on this? I've already made this refactoring but some reviewer wanted me to revert it. I don't remember who.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I with @DmitryOlshansky here - unnecessary nesting of templates creates potential combinatoric template bloat and no D compiler is currently capable of merging identical binary blocks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's also a little confusing from a readability perspective.

I really wish this type didn't have to be a template to solve this problem, but I don't know of any solutions myself...

@DmitryOlshansky
Copy link
Member

Looking good overall

@nordlow
Copy link
Contributor Author

nordlow commented Nov 30, 2014

And rebased.

@nordlow
Copy link
Contributor Author

nordlow commented Dec 2, 2014

Moved RangeT to global scope as requested.

@aG0aep6G
Copy link
Contributor

aG0aep6G commented Dec 7, 2014

On Wed, Nov 26, 2014 at 8:06 PM, JakobOvrum notifications@github.com
wrote:

All the positional insert and remove methods now only work when given
mutable positions (i.e. Array.Range), which may or may not make sense.

This hasn't changed, has it? They took a (mutable) Range before, too. Maybe
we could lift that restriction, but I think that should be done in another
pull.

Like before, one has to obtain a Range from a mutable Array for mutating
operations. This may not be strictly necessary, but it's fairly reasonable.

@nordlow
Copy link
Contributor Author

nordlow commented Dec 8, 2014

This hasn't changed, has it? They took a (mutable) Range before, too. Maybe

I'm not sure what is the best choice here regarding mutablity of Range.

we could lift that restriction, but I think that should be done in another
pull.

I vote for a separate pull.

@aG0aep6G
Copy link
Contributor

Ping again?

@nordlow
Copy link
Contributor Author

nordlow commented Jan 15, 2015

Is there something you expect me to add here?

If the problem is mutability issues could you please show me a unittest that currently fails that should pass.

I'm not skilled enough in Phobos policies to decide whether positional inserts and removes should require mutability of Range or not. @andralex @WalterBright ?

@nordlow
Copy link
Contributor Author

nordlow commented Jan 20, 2015

Ping.

@quickfur
Copy link
Member


public import std.container.util;

private static struct RangeT(A)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static for structs is a no-op at module level

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall I remove?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@JakobOvrum
Copy link
Contributor

I'd still prefer a more general solution involving conversions between const(C.Range!T) and C.Range!(const T), but this patch seems forward-compatible with such a solution (except possible deprecation of C.ConstRange and C.ImmutableRange), so LGTM.

@JakobOvrum
Copy link
Contributor

I'll merge it in a day or so unless someone finds new evidence against it until then.

@JakobOvrum
Copy link
Contributor

Quite a few commits here, please squash.

@andralex
Copy link
Member

squash

@andralex
Copy link
Member

after that green light @JakobOvrum

@nordlow
Copy link
Contributor Author

nordlow commented Jan 28, 2015

Done. I did an interactive rebase. I hope that is what you wanted me to do.

@JakobOvrum
Copy link
Contributor

Auto-merge toggled on

JakobOvrum added a commit that referenced this pull request Jan 29, 2015
@JakobOvrum JakobOvrum merged commit 224238a into dlang:master Jan 29, 2015
@nordlow nordlow deleted the inout-array-range branch January 29, 2015 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants