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

RFC: Deprecate Int-Char comparisons, e.g. 'x' == 120 #16024

Merged
merged 2 commits into from
May 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions base/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1325,11 +1325,11 @@ AnyDict(
i = position(buf)
if i != 0
c = buf.data[i]
if c == '\n' || c == '\t' ||
if c == UInt8('\n') || c == UInt8('\t') ||
# hack to allow path completion in cmds
# after a space, e.g., `cd <tab>`, while still
# allowing multiple indent levels
(c == ' ' && i > 3 && buf.data[i-1] == ' ')
(c == UInt8(' ') && i > 3 && buf.data[i-1] == UInt8(' '))
edit_insert(s, " "^4)
return
end
Expand Down
2 changes: 1 addition & 1 deletion base/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ function hist_from_file(hp, file)
while !isempty(line)
push!(lines, chomp(line[2:end]))
eof(file) && break
ch = Base.peek(file)
ch = Char(Base.peek(file))
ch == ' ' && error(munged_history_message, countlines)
ch != '\t' && break
line = hist_getline(file)
Expand Down
7 changes: 1 addition & 6 deletions base/char.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,7 @@ isempty(c::Char) = false
in(x::Char, y::Char) = x == y

==(x::Char, y::Char) = UInt32(x) == UInt32(y)
==(x::Char, y::Integer) = UInt32(x) == y
==(x::Integer, y::Char) = x == UInt32(y)

isless(x::Char, y::Char) = isless(UInt32(x), UInt32(y))
isless(x::Char, y::Integer) = isless(UInt32(x), y)
isless(x::Integer, y::Char) = isless(x, UInt32(y))
isless(x::Char, y::Char) = UInt32(x) < UInt32(y)

-(x::Char, y::Char) = Int(x) - Int(y)
-(x::Char, y::Integer) = Char(Int32(x) - Int32(y))
Expand Down
2 changes: 1 addition & 1 deletion base/datafmt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function countlines(io::IO, eol::Char='\n')
while !eof(io)
nb = readbytes!(io, a)
@simd for i=1:nb
@inbounds nl += a[i] == eol
@inbounds nl += a[i] == UInt8(eol)
end
end
nl
Expand Down
8 changes: 8 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,14 @@ end
@deprecate_binding UTF8String String
@deprecate_binding ByteString String

@deprecate ==(x::Char, y::Integer) UInt32(x) == y
@deprecate ==(x::Integer, y::Char) x == UInt32(y)
@deprecate isless(x::Char, y::Integer) UInt32(x) < y
@deprecate isless(x::Integer, y::Char) x < UInt32(y)
# delete these methods along with deprecations:
isequal(x::Char, y::Integer) = false
isequal(x::Integer, y::Char) = false

# During the 0.5 development cycle, do not add any deprecations below this line
# To be deprecated in 0.6

Expand Down
2 changes: 1 addition & 1 deletion base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ hash(x::UInt64, h::UInt) = hx(x, Float64(x), h)
hash(x::Int64, h::UInt) = hx(reinterpret(UInt64,abs(x)), Float64(x), h)
hash(x::Float64, h::UInt) = isnan(x) ? (hx_NaN $ h) : hx(box(UInt64,fptoui(unbox(Float64,abs(x)))), x, h)

hash(x::Union{Bool,Char,Int8,UInt8,Int16,UInt16,Int32,UInt32}, h::UInt) = hash(Int64(x), h)
hash(x::Union{Bool,Int8,UInt8,Int16,UInt16,Int32,UInt32}, h::UInt) = hash(Int64(x), h)
hash(x::Float32, h::UInt) = hash(Float64(x), h)

## precision, as defined by the effective number of bits in the mantissa ##
Expand Down
2 changes: 1 addition & 1 deletion base/markdown/Common/block.jl
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ function list(stream::IO, block::MD)
c = read(stream, Char)
if c == '\n'
eof(stream) && break
next = peek(stream)
next = Char(peek(stream)) # ok since we only compare with ASCII
if next == '\n'
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't it be better to leave next as a byte here and compare with UInt8('\n')?

Copy link
Member

Choose a reason for hiding this comment

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

Performance-wise, both solutions seem to give the same native code. I just tried with:

function f(x)
     for c in x
         Char(c) == '\n' && return true
     end
     false
 end

function g(x)
     for c in x
         c == UInt8('\n') && return true
     end
     false
 end

code_native(f, (Vector{UInt8},))
code_native(g, (Vector{UInt8},))

But as regards style, I prefer converting to Char.

break
else
Expand Down
2 changes: 1 addition & 1 deletion base/markdown/Julia/interp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ end

function interpinner(stream::IO, greedy = false)
startswith(stream, '$') || return
(eof(stream) || peek(stream) in whitespace) && return
(eof(stream) || Char(peek(stream)) in whitespace) && return
try
return Base.parse(stream::IOBuffer, greedy = greedy)
catch e
Expand Down
4 changes: 3 additions & 1 deletion base/markdown/parse/parse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ function parseinline(stream::IO, md::MD, config::Config)
content = []
buffer = IOBuffer()
while !eof(stream)
char = peek(stream)
# FIXME: this is broken if we're looking for non-ASCII
Copy link
Member

Choose a reason for hiding this comment

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

Woudn't peekchar fix this problem?

Copy link
Member

Choose a reason for hiding this comment

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

we need peek to match the current read interface:

read(io, UInt8)
read(io, Char)

peek(io, UInt8)
peek(io, Char)

with the defaults matching.

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

Unfortunately, peekchar only works for the IOStream type, so this fails.

# characters because peek only returns a single byte.
char = Char(peek(stream))
if haskey(config.inner, char) &&
(inner = parseinline(stream, md, config.inner[char])) !== nothing
c = takebuf_string(buffer)
Expand Down
6 changes: 3 additions & 3 deletions base/markdown/parse/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const whitespace = " \t\r"
Skip any leading whitespace. Returns io.
"""
function skipwhitespace(io::IO; newlines = true)
while !eof(io) && (peek(io) in whitespace || (newlines && peek(io) == '\n'))
while !eof(io) && (Char(peek(io)) in whitespace || (newlines && peek(io) == UInt8('\n')))
read(io, Char)
end
return io
Expand Down Expand Up @@ -82,7 +82,7 @@ function startswith(stream::IO, s::AbstractString; eat = true, padding = false,
end

function startswith(stream::IO, c::Char; eat = true)
if !eof(stream) && peek(stream) == c
if !eof(stream) && peek(stream) == UInt8(c)
eat && read(stream, Char)
return true
else
Expand Down Expand Up @@ -181,7 +181,7 @@ function parse_inline_wrapper(stream::IO, delimiter::AbstractString; rep = false
startswith(stream, delimiter^n) || return nothing
while startswith(stream, delimiter); n += 1; end
!rep && n > nmin && return nothing
!eof(stream) && peek(stream) in whitespace && return nothing
!eof(stream) && Char(peek(stream)) in whitespace && return nothing

buffer = IOBuffer()
while !eof(stream)
Expand Down
4 changes: 2 additions & 2 deletions base/printf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ function gen_e(flags::String, width::Int, precision::Int, c::Char, inside_g::Boo
# print sign
'+' in flags ? push!(blk.args, :(write(out, neg?'-':'+'))) :
' ' in flags ? push!(blk.args, :(write(out, neg?'-':' '))) :
push!(blk.args, :(neg && write(out, '-')))
push!(blk.args, :(neg && write(out, '-')))
# print zero padding
if padding !== nothing && !('-' in flags) && '0' in flags
push!(blk.args, pad(width, padding, '0'))
Expand All @@ -468,7 +468,7 @@ function gen_e(flags::String, width::Int, precision::Int, c::Char, inside_g::Boo
if precision > 0
if inside_g && !('#' in flags)
push!(blk.args, :(endidx = $ndigits;
while endidx > 1 && DIGITS[endidx] == '0'
while endidx > 1 && DIGITS[endidx] == UInt8('0')
endidx -= 1
end;
if endidx > 1
Expand Down
3 changes: 2 additions & 1 deletion test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ a = [0,1,2,3,0,1,2,3]

# find with general iterables
s = "julia"
@test find(s) == [1,2,3,4,5]
# FIXME once 16269 is resolved
# @test find(s) == [1,2,3,4,5]
@test find(c -> c == 'l', s) == [3]
g = graphemes("日本語")
@test find(g) == [1,2,3]
Expand Down
24 changes: 13 additions & 11 deletions test/char.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#tests for /base/char.jl

@test typemin(Char) == 0
@test typemin(Char) == Char(0)
@test ndims(Char) == 0
@test getindex('a', 1) == 'a'
@test_throws BoundsError getindex('a',2)
Expand Down Expand Up @@ -133,44 +133,44 @@ let

#isless(x::Char, y::Integer) = isless(UInt32(x), y)
for x in upperchars
@test isless(x, 91) == true
@test isless(x, Char(91)) == true
end

for x in lowerchars
@test isless(x, 123) == true
@test isless(x, Char(123)) == true
end

for x in numberchars
@test isless(x, 66) == true
@test isless(x, Char(66)) == true
end

for x in plane1_playingcards
@test isless(x, 127151) == true
@test isless(x, Char(127151)) == true
end

for x in plane2_cjkpart1
@test isless(x, 131088) == true
@test isless(x, Char(131088)) == true
end

#isless(x::Integer, y::Char) = isless(x, UInt32(y))
for x in upperchars
@test isless(64, x) == true
@test isless(Char(64), x) == true
end

for x in lowerchars
@test isless(96, x) == true
@test isless(Char(96), x) == true
end

for x in numberchars
@test isless(47, x) == true
@test isless(Char(47), x) == true
end

for x in plane1_playingcards
@test isless(127135, x) == true
@test isless(Char(127135), x) == true
end

for x in plane2_cjkpart1
@test isless(131071, x) == true
@test isless(Char(131071), x) == true
end
end #end of let block

Expand All @@ -191,3 +191,5 @@ let
@test array == ['a', 'a', 'a']
@test eltype(array) == Char
end

@test !isequal('x', 120)
4 changes: 2 additions & 2 deletions test/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ let mt = MersenneTwister()
srand(mt)
@test rand(mt, 0:3:1000) in 0:3:1000
@test issubset(rand!(mt, Array(Int, 100), 0:3:1000), 0:3:1000)
coll = Any[2, UInt128(128), big(619), "string", 'c']
coll = Any[2, UInt128(128), big(619), "string"]
@test rand(mt, coll) in coll
@test issubset(rand(mt, coll, 2, 3), coll)

Expand Down Expand Up @@ -315,7 +315,7 @@ for rng in ([], [MersenneTwister()], [RandomDevice()])
rand!(rng..., BitArray(5)) ::BitArray{1}
rand!(rng..., BitArray(2, 3)) ::BitArray{2}

for T in [Base.BitInteger_types..., Bool, Char, Float16, Float32, Float64]
for T in [Base.BitInteger_types..., Bool, Float16, Float32, Float64]
a0 = rand(rng..., T) ::T
a1 = rand(rng..., T, 5) ::Vector{T}
a2 = rand(rng..., T, 2, 3) ::Array{T, 2}
Expand Down
6 changes: 3 additions & 3 deletions test/read.jl
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,9 @@ f = joinpath(dir, "test.txt")
open(io->write(io, "123"), f, "w")
f1 = open(f)
f2 = Base.Filesystem.open(f, Base.Filesystem.JL_O_RDONLY)
@test read(f1, UInt8) == read(f2, UInt8) == '1'
@test read(f1, UInt8) == read(f2, UInt8) == '2'
@test read(f1, UInt8) == read(f2, UInt8) == '3'
@test read(f1, UInt8) == read(f2, UInt8) == UInt8('1')
@test read(f1, UInt8) == read(f2, UInt8) == UInt8('2')
@test read(f1, UInt8) == read(f2, UInt8) == UInt8('3')
@test_throws EOFError read(f1, UInt8)
@test_throws EOFError read(f2, UInt8)
close(f1)
Expand Down
2 changes: 2 additions & 0 deletions test/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,5 @@ let s = Set(1:5)
end

@test pop!(Set(1:2), 2, nothing) == 2

@test length(Set(['x',120])) == 2
4 changes: 2 additions & 2 deletions test/spawn.jl
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ let out = Pipe(), echo = `$exename -f -e 'print(STDOUT, " 1\t", readstring(STDIN
wait(ready) # wait for writer task to be ready before using `out`
@test nb_available(out) == 0
@test endswith(readuntil(out, '1'), '1')
@test read(out, UInt8) == '\t'
@test Char(read(out, UInt8)) == '\t'
c = UInt8[0]
@test c == read!(out, c)
Base.wait_readnb(out, 1)
Expand All @@ -288,7 +288,7 @@ let out = Pipe(), echo = `$exename -f -e 'print(STDOUT, " 1\t", readstring(STDIN
@test !iswritable(out)
@test !isopen(out)
@test nb_available(out) == 0
@test c == ['w']
@test c == UInt8['w']
@test lstrip(ln2) == "1\thello\n"
@test ln1 == "orld\n"
@test isempty(read(out))
Expand Down
2 changes: 1 addition & 1 deletion test/strings/basic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ str = "abcdef\uff\uffff\u10ffffABCDEF"
@test typeof(lowercase(utf16(str))) == UTF16String
@test typeof(lowercase(utf32(str))) == UTF32String

foomap(ch) = (ch > 65)
foomap(ch) = (ch > Char(65))
foobar(ch) = Char(0xd800)
foobaz(ch) = reinterpret(Char, typemax(UInt32))
@test_throws UnicodeError map(foomap, utf16(str))
Expand Down
26 changes: 13 additions & 13 deletions test/unicode/utf32.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
u8 = "\U10ffff\U1d565\U1d7f6\U00066\U2008a"
u32 = utf32(u8)
@test sizeof(u32) == 20
@test length(u32.data) == 6 && u32.data[end] == Char(0)
@test length(u32.data) == 6 && u32.data[end] == 0
@test length(u32) == 5
@test utf8(u32) == u8
@test collect(u8) == collect(u32)
Expand Down Expand Up @@ -181,13 +181,13 @@ for (fun, S, T) in ((utf16, UInt16, UTF16String), (utf32, UInt32, UTF32String))
str = "abcd\0\uff\u7ff\u7fff\U7ffff"
tst = SubString(convert(T,str),4)
cmp = Char['d','\0','\uff','\u7ff','\u7fff','\U7ffff']
cmpch = Char['d','\0','\uff','\u7ff','\u7fff','\U7ffff','\0']
cmp32 = UInt32['d','\0','\uff','\u7ff','\u7fff','\U7ffff','\0']
cmp16 = UInt16[0x0064,0x0000,0x00ff,0x07ff,0x7fff,0xd9bf,0xdfff,0x0000]
x = fun(tst)
cmpx = (S == UInt16 ? cmp16 : cmpch)
cmpx = (S == UInt16 ? cmp16 : cmp32)
@test typeof(tst) == SubString{T}
@test convert(T, tst) == str[4:end]
S != UInt32 && @test convert(Vector{Char}, x) == cmp
@test convert(Vector{Char}, x) == cmp
# Vector{T} / Array{T}
@test convert(Vector{S}, x) == cmpx
@test convert(Array{S}, x) == cmpx
Expand Down Expand Up @@ -223,9 +223,9 @@ let str = ascii("this ")
@test typeof(p8) == Ptr{UInt8}
@test unsafe_load(p8,1) == 0x74
@test typeof(p16) == Ptr{UInt16}
@test unsafe_load(p16,1) == 0x0074
@test unsafe_load(p16,1) == 0x74
@test typeof(p32) == Ptr{UInt32}
@test unsafe_load(p32,1) == 't'
@test unsafe_load(p32,1) == 0x74
pa = pointer(str, 2)
p8 = pointer(u8, 2)
p16 = pointer(u16, 2)
Expand All @@ -235,10 +235,10 @@ let str = ascii("this ")
@test typeof(p8) == Ptr{UInt8}
@test unsafe_load(p8,1) == 0x68
@test typeof(p16) == Ptr{UInt16}
@test unsafe_load(p16,1) == 0x0068
@test unsafe_load(p16,1) == 0x68
@test typeof(p32) == Ptr{UInt32}
@test unsafe_load(p32,1) == 'h'
s8 = SubString{String}(u8, 3, 5)
@test unsafe_load(p32,1) == 0x68
s8 = SubString{String}(u8, 3, 5)
s16 = SubString{UTF16String}(u16, 3, 5)
s32 = SubString{UTF32String}(u32, 3, 5)
p8 = pointer(s8)
Expand All @@ -247,18 +247,18 @@ let str = ascii("this ")
@test typeof(p8) == Ptr{UInt8}
@test unsafe_load(p8,1) == 0x69
@test typeof(p16) == Ptr{UInt16}
@test unsafe_load(p16,1) == 0x0069
@test unsafe_load(p16,1) == 0x69
@test typeof(p32) == Ptr{UInt32}
@test unsafe_load(p32,1) == 'i'
@test unsafe_load(p32,1) == 0x69
p8 = pointer(s8, 2)
p16 = pointer(s16, 2)
p32 = pointer(s32, 2)
@test typeof(p8) == Ptr{UInt8}
@test unsafe_load(p8,1) == 0x73
@test typeof(p16) == Ptr{UInt16}
@test unsafe_load(p16,1) == 0x0073
@test unsafe_load(p16,1) == 0x73
@test typeof(p32) == Ptr{UInt32}
@test unsafe_load(p32,1) == 's'
@test unsafe_load(p32,1) == 0x73
end

@test isvalid(Char['f','o','o','b','a','r'])