Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update from_array to prevent a copy (issue #1097) #1423

Merged
merged 1 commit into from
Nov 18, 2016
Merged

Update from_array to prevent a copy (issue #1097) #1423

merged 1 commit into from
Nov 18, 2016

Conversation

Perelandric
Copy link
Contributor

The String.from_array method previously was documented to only reuse
the underlying Array[U8] if it ended with a 0 byte, otherwise the
Array would be copied with the 0 added to the end. However, the
behavior was such that the no-copy version would make the trailing 0
the last character of the String instead of a terminator, and changing
that behavior caused other issues.

Since pony Strings may now be non-null-terminated, the new behavior of
.from_array is to always use the entire underlying Array, without
regard to the presence of a trailing 0 byte.

The documentation is also updated and tests added.

The `String.from_array` method previously was documented to only reuse
the underlying `Array[U8]` if it ended with a `0` byte, otherwise the
Array would be copied with the `0` added to the end. However, the
behavior was such that the no-copy version would make the trailing `0`
the last character of the String instead of a terminator, and changing
that behavior caused other issues.

Since pony Strings may now be non-null-terminated, the new behavior of
`.from_array` is to always use the entire underlying Array, without
regard to the presence of a trailing `0` byte.

The documentation is also updated and tests added.
@Perelandric
Copy link
Contributor Author

Side note... both previously and currently, the _alloc is set to the same size as that of the underlying array that is being reused.

_alloc = data.space()

If the Array[U8] is over-allocated, that extra allocation will be retained, which doesn't seem to make sense for a String val... unless maybe it does if the new String is being recovered to a mutable type?

Just wanted to throw that out there.

@Perelandric
Copy link
Contributor Author

Perelandric commented Nov 17, 2016

Another thought... this is now almost identical to String.from_iso_array. Are both needed? Seems like String.from_array could just be used by consuming the Array[U8] iso.

@jemc
Copy link
Member

jemc commented Nov 18, 2016

Another thought... this is now almost identical to String.from_iso_array. Are both needed? Seems like String.from_array could just be used by consuming the Array[U8] iso.

The from_iso_array method can use an iso array to create an iso string, which could be consumed to a val if needed. The from_array method can use a val array, or an iso array consumed to a val to create a val string.

That is, possibility-wise, we have these two kinds of transformations (ignoring other rcaps for the moment):

Array iso => (String iso | String val)
(Array iso | Array val) => String val

I don't think we can safely eliminate either without losing possibilities. Removing the former means there is no way to end up with a String iso. Removing the latter means there is no way to use an Array val.

However, I'm hoping that a combination of generic type inference (ponylang/rfcs#26) and compile-time specialization (ponylang/rfcs#62) will save us here, when implemented. Then we could have something like:

new val from_array[A: (Array[U8] val | Array[U8] iso)](data: A) iftype A <: Array[U8] val =>
  // ...

new iso from_array[A: (Array[U8] val | Array[U8] iso)](data: A) iftype A <: Array[U8] iso =>
  // ...

@Perelandric
Copy link
Contributor Author

Thanks @jemc, you're right. I was thinking there was enough magic/restriction in a recover to be able to recover a val to an iso but I see now that's not the case.

It would be interesting to see a recover expression wherein its restrictions change based on the capability to which you're recovering. So recovering to an iso would ensure that the recovered value was never sent or assigned to anything that could escape the block, allowing the compiler to perform otherwise invalid rcap conversions.

let a: Array[U8] val = recover ['a', 'b', 'c'] end 

let s = recover iso
  // Make a String val
  let s = String.from_array(a)

  // ...

  s // Enforces that the String never escaped in any way except as the result
end 

Anyway, that's just off the top of my head. Perhaps it would be too confusing or problematic in other ways.

@jemc jemc added the changelog - changed Automatically add "Changed" CHANGELOG entry on merge label Nov 18, 2016
@jemc
Copy link
Member

jemc commented Nov 18, 2016

At any rate, this dicsussion is a side point to the central issue this PR resolves, so I'm merging. Thanks for the fix!

@jemc jemc merged commit 726d6b8 into ponylang:master Nov 18, 2016
ponylang-main added a commit that referenced this pull request Nov 18, 2016
@Perelandric Perelandric deleted the string_from_array branch November 18, 2016 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog - changed Automatically add "Changed" CHANGELOG entry on merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants