Crystal: Weird Slice#pointer method semantics

Created on 29 Oct 2018  路  5Comments  路  Source: crystal-lang/crystal

Hi, I'm not really sure what is going on with this method: Slice#pointer

  1. It takes size argument, which is supposed to do some kind of bounds checking, but it's off by one, as far as I can see.
  2. No matter what size value you pass, it returns the same pointer (I think it was supposed to return different addresses depending on size).
  3. A bit unrelated, but right now there is no explicit way to say that you want to get a pointer from slice without passing any 'dummy argument', I'm not counting to_unsafe as explicit.
help-wanted stdlib

Most helpful comment

Yeah, that method wasn't proposed by me and I always found it a bit odd. I think we can safely remove it.

All 5 comments

@Heaven31415 you're meant to pass as an argument the number of offsets from the pointer you're going to use. So slice.pointer(5) means you can use slice.pointer(5)[0..4]. It's supposed to just return the pointer, it only does bounds checking, no pointer arithmetic. For getting the pointer without bounds checking to_unsafe is fine.

Yeah, that method wasn't proposed by me and I always found it a bit odd. I think we can safely remove it.

@asterite I was checking the reason why Slice#pointer and I found this commit https://github.com/crystal-lang/crystal/commit/22c7881586c6214896485745d109815f545f0ec5
It seems that this method provide a validation layer and it's mentioned in the docs that Slice performs bound checks: (link)

A Slice is a Pointer with an associated size.
While a pointer is unsafe because no bound checks are performed when reading from and writing to it, reading from and writing to a slice involve bound checks. In this way, a slice is a safe alternative to Pointer.

Also, I tried locally to use Slice#to_unsafe instead of Slice#pointer and the following example doesn't raise an exception:
https://github.com/crystal-lang/crystal/blob/master/src/slice.cr#L320
is it safer in this case to keep it?

The copy and move methods rely on the behaviour of #pointer for bounds checking. That would still need to be implemented in these methods.

I agree that this method should be removed, because it doesn't make much sense: It applies a bounds check but returns a pointer which has no bounds. There are only a hand full of uses in stdlib. Most are related to copy and move methods and look like a.copy_to(b.pointer(size), b.size). That could just be a.copy_to(b) anyway.

But there are also other cases like LibSSL.ssl_read(@ssl, slice.pointer(count), count) which would read more intuitively when written like this:

checked = slice[0, count]
LibSSL.ssl_read(@ssl, checked.to_unsafe, checked.size)

@Maroo-b I know, I was there when it was written (we did it together with waj) but I personally never felt the need for it, nor like it... but I usually trust waj's thoughts and ideas more than mines, so it might be fine.

Was this page helpful?
0 / 5 - 0 ratings