-
Notifications
You must be signed in to change notification settings - Fork 0
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
Collaboration proposal #1
Comments
Thanks for your offer and your input. I'd like to accept your offer. You make a very good point about making the API more readable. Honestly, I never liked the current style with Given your comment on slices, I'd like to clarify that (as I meant it) this crate is about obtaining a "sub-array" not working on "sub-array"s. And thus, it is quite sensible (in my opinion) to extract a "sub-array" from a slice, tho it is true that this operation can't be checked at compile time and thus generally may panic at run-time. Nevertheless, I would say that slices as a source should be at most of secondary concern, but I would rather keep them. Anyway, as far as I understand, this is concisely what you are proposing:
At first glance, I supposed all of these enhancements would require the Nightly Thus, I consider the following plan:
Separating those two points will allow users to keep using this crate with a stable compiler, tho without compile-time constraints, which at least is consistent with the current implementation, at least they get a nicer API. And for those who can afford to use Nightly, they get the compile-time constraints as well. Some further notes:
Of course, I also looked into the playground example code that you kindly provided. You did there some nice ground work. Some points which I found can be improved/fixed:
Here a refined version of your code, that fixes the above. In terms of a future API there is the aforementioned panicing variant, that should work with stable Rust and may work with slices, which I imaging to look something like this: // The trait providing the API
use sub_array::CheckedSubArray;
use sub_array::range;
let slice: &[u8] = &[1,2,3,4,5];
// works
let sub_array: &[u8;2] = slice.checked_sub_array_ref(range!(3..5)).unwrap();
assert_eq!(sub_array, [4,5]);
// compiles, but panics
let sub_array: &[u8;2] = slice.checked_sub_array_ref(range!(4..6)).unwrap(); Basically the current API, (mostly) same semantics, same source types (arrays work as well), but with more verbose names to make "space" for the constraint version. As you can see, I began to like a "checked" version that returns an And then the Nightly feature-gated compile-time enforce variant: #![feature(generic_const_exprs)]
// The trait providing the API
use sub_array::SubArray;
use sub_array::range;
let array: &[u8; 5] = &[1,2,3,4,5];
// works
let sub_array: &[u8;2] = array.sub_array_ref(range!(3..5));
assert_eq!(sub_array, [4,5]);
// wouldn't even compile
//let sub_array: &[u8;2] = array.sub_array_ref(range!(4..6)); And of course, the Nightly variant would also allow indexing with the same semantics as above: #![feature(generic_const_exprs)]
// (Const)Range is all we need
use sub_array::range;
let array: &[u8; 5] = &[1,2,3,4,5];
// works
let sub_array: &[u8;2] = &array[range!(3..5)];
assert_eq!(sub_array, [4,5]);
// wouldn't even compile
//let sub_array: &[u8;2] = &array[range!(4..6)]; What do you think about all that? |
Wow! You took the idea and ran with it! Nice :) Basically each of your comments I agree with. Nice work on making it all just BETTER.
This is probably the most glaringly obvious thing I overlooked. Well spotted! That makes it all much nicer.
Yep, you're 100% right. For some reason I'm in a "const check everything" mindset, and it's easy to overlook other use-cases. There is no reason not to extend the API to slices too. Nice!
Mmm... I think I understand your concern. If we had exactly the same API and all that adding the The strange situation is that we'd only be breaking programs that would DEFINITELY panic. Although, only if it hits that case at runtime, which it may not. Not sure how strict semver is in this situation, but IMO this may be a grey area. The alternate is just to do a major version bump when that upgrade happens. Then we don't break programs but allow for the more ergonomic API in the current panic-able version. So I guess the question is: "Which is more important, not having a major version bump, or having an ergonomic API?"
All of them are better! NICE!
I like the idea of a checked variant 👍 But I do think that the unchecked variant would be useful too (You've completely convinced me of the slice use-case :P). So the unchecked variant could use the A note on naming: I'm not sure the Anyway, this is exciting! Thanks for being open to collaboration! I think this would turn into an extremely useful crate! |
I can code up a PR to get the ball rolling. Just want to co-ordinate that we don't both start implementing and have wasted effort. Let me know if you'd rather do it yourself or if you have thoughts on the above comment. Will likely start implementing in a day or so. |
Sorry, for the late answer. I'm a little bit busy currently, so it sounds quite good to me, if you like to start an PR. About your comment regarding semver: an "in-place" upgrade from panicking to compile-time errors would be definitely a breaking change, and there are multiple reason why this would be very bad here, for once, a program that panics is strictly speaking still a valid program (tho probably not very useful), so preventing them from compiling breaks them. More practically examples are:
However, there are actually wrong programs those exhibiting undefined behavior (very different from panics), and fixing them is typically not consider a breaking change, because they were totally broken before, but that does not apply here. Actually, in my mind, I always assumed that the new API will be a breaking/major change. So I'm cool with making a breaking change, much rather than accidentally breaking someone else's code. About the checked-ness: I totally agree that the checked variant is nice and that it would be useful to also have an "unchecked" panicking variant. But I'm not sure what a nice API would be: literal writing However on a seemingly unrelated note, I also noticed that when we rewrite the API to only use the So I though maybe we could jointly solve these two issues by introducing a second "ConstRange" type and macro, one that isn't "fully const" but rather "half const" i.e. having a const size but a variable offset (sort of how the current API works). I'm kinda struggling with a good name for it, maybe something like Then we can still support the arbitrary offset use-case while also having a distinguishing feature to implement directly panicking indexing:
Lastly, about naming: I actually wasn't that much aware about the "missing" |
Hi, just touching base again. Haven't forgotten about this but things got a bit busy my side. I still intend to do this PR but after reading your [great] suggestions I've realised it's a bit larger than I originally thought. Just letting you know I haven't disappeared. |
I like your idea! And the name! (hence why I'm asking to collaborate rather than publishing my own crate).
How do you feel about trying to make this api a bit closer to the normal slicing API?
I've played around a bit and the closest I can get is this:
I think with a little extra
proc_macro
trickery we may be able to get to the following:The main value I believe this crate would bring is to provide a safe API for doing sub-array slicing on arrays. You can enforce the safety via compile time constraints using trait bounds. This is unfortunately not possible using slices, so I would also propose the API on slices get removed. It feels a bit strange to have it in a crate with the word
array
in anyway.There definitely are some disadvantages of doing what I'm suggesting. The main one is that it requires
generic_const_exprs
feature to do the trait bound constraints, which is still unstable. This means the consumers of this library need to use thenightly
compiler until it get stabilised.Have a look at this playground to get an idea of what I'm suggesting.
The main thing you may notice where I've gone in a separate direction from you is the use of the
SubArray
wrapper struct. This is to allow overloading of theIndex
trait. I'm not married to the idea, but I do think it has some advantages.Let me know what you think! :)
The text was updated successfully, but these errors were encountered: