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

Added type restrictions to many collections methods. Fixes #1764 #1851

Closed
wants to merge 1 commit into from

Conversation

asterite
Copy link
Member

@asterite asterite commented Nov 1, 2015

This fixes #1764 and #988 by adding type restrictions to methods like includes? and delete.

Just adding this helped me find a bug in the compiler: a case wasn't handled and a variable remained nil, and it could leak into these delete and includes? checks just fine.

I had to remove some Set specs that involved sets of different types, like Set{1, 2, 3} - Set{1, 'a'}. I checked some local projects against this PR and they all compiled fine, except one where I had to be a bit more strict, but it definitely helped me rethink those "unexpected" cases a bit more, so it didn't feel like something annoying. So removing those Set specs should be OK, in practice those cases don't seem to appear. If they do, we can think of alternative methods.

It would be nice if you could test the compiler with this PR applied against your projects and see if it breaks code, or if you find a case where you definitely need the old functionality.

@@ -46,7 +46,7 @@ module HTTP
bytesize = line.bytesize

# Get the colon index and name
colon_index = cstr.to_slice(bytesize).index(':'.ord) || 0
colon_index = cstr.to_slice(bytesize).index(':'.ord.to_u8) || 0
Copy link
Contributor

Choose a reason for hiding this comment

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

here was bug or not?

Copy link
Member Author

Choose a reason for hiding this comment

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

@kostya Not a bug because index checks for equality and it works with different kinds of integers. With this change I have to put the specific type, but I think these conversions will be rare, so it's ok.

@kostya
Copy link
Contributor

kostya commented Nov 1, 2015

i checked my relative big project, find 2 bugs in specs, which test nothing, because always pass.

@ysbaddaden
Copy link
Contributor

I just found one boring case (not a deal breaker):

[1, "1", true, "true"].includes?(1_i64)
  • It passes if I specify all 1_i8, 1_i16 (boring but okayish).
  • The compiler crashes if I try [1 as Int, "1"] with "Bug: trying to upcast Int <- Int32".
  • The compiler fails for [1 as Int] with "can't use Int as generic type argument yet".

@asterite
Copy link
Member Author

asterite commented Nov 2, 2015

Yes, the only cases I found it "broke" was when different int/float types, so it shouldn't be that terrible (you can always to_i) and will help catch real mistakes. The as Int is probably an unrelated bug.

@kostya
Copy link
Contributor

kostya commented Nov 22, 2015

i think better extend restriction to T?, because nil is common case of no value.

example:

# seems better
if v = bla[x]?
  p v
end

# than
if x && (v = bla[x]?)
  p v
end

# checking for x here make no sense

in my project i was need to add 10 times this check.

@asterite
Copy link
Member Author

@kostya Yes, in a project of mine I also had this issue. T? doesn't sound that bad, leaking a nil value there is probably safe.

@kostya
Copy link
Contributor

kostya commented Feb 9, 2016

also spend some time to find this bug:

b = BitArray.new(10000)
if b[100] == 0
  ...
end

condition always false because comparing different types. i think crystal at least can show the warning.

@refi64
Copy link
Contributor

refi64 commented Mar 21, 2016

Bump?

@asterite
Copy link
Member Author

@kirbyfan64 Not sure what the best thing to do here would be. Maybe nil should also be accepted as an argument in []? methods.

@bcardiff
Copy link
Member

Sorry I've been playing around with clojure lately.
if we had

class Object
  def in(a)
    a[self]?
  end
end

We could write key.in(hash) or key.try &.in(hash)
But it reads awfully probably.

If we accept K? as key argument for #[]? methods then we remove the change of using nil as a key which is kind of drastic, but I could accept. But most important it will prevent bubbling errors when more complex expressions used in the key are nilable without the awareness of the user.

Maybe is ok to use K? for #[]?. And K for #[] . But we should guarantee that obj[nil] = x => obj[nil]? = x

@refi64
Copy link
Contributor

refi64 commented Jul 14, 2016

:(

@asterite
Copy link
Member Author

@kirbyfan64 #2996 ;-)

@asterite asterite deleted the collections_type_restrictions branch April 27, 2018 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

compiler not restricted types of hash keys
6 participants