diff --git a/.gitignore b/.gitignore index 2b32c354aa4af..1a9ca24e0df97 100644 --- a/.gitignore +++ b/.gitignore @@ -16,5 +16,7 @@ *.obj *.dylib *.dSYM +*.jl.cov +*.jl.mem .DS_Store diff --git a/.mailmap b/.mailmap index 0fedc2522b32d..1ad0a3339ab9d 100644 --- a/.mailmap +++ b/.mailmap @@ -182,3 +182,5 @@ Tracy Wadleigh Tracy Wadleigh Mike Innes + +Sean Garborg diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e948e06519449..981ed0b67e82f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,13 +70,17 @@ Julia's documentation is stored in the `doc` directory, and like everything else The Julia community uses [GitHub issues](https://github.com/JuliaLang/julia/issues) to track and discuss problems, feature requests, and pull requests. You can make pull requests for incomplete features to get code review. The convention is to prefix the pull request title with "WIP:" for Work In Progress, or "RFC:" for Request for Comments when work is completed and ready for merging. This will prevent accidental merging of work that is in progress. -Note: These instructions are for adding functionality to the base library. Usually, this is not encouraged, and before doing so, it is essential to discuss the proposed changes or additions on the mailing list or in a github issue. Changing stuff in the base can potentially break a lot of things. Make sure you test your code as described here, together with the latest Julia updates, to avoid problems. Add new code to Julia's base libraries as follows: +Note: These instructions are for adding to or improving functionality in the base library. Before getting started, it can be helpful to discuss the proposed changes or additions on the mailing list or in a github issue---it's possible your proposed change belongs in a package rather than the core language. Also, keep in mind that changing stuff in the base can potentially break a lot of things. Finally, because of the time required to build julia, note that it's usually faster to develop your code in stand-alone files, get it working, and then migrate it into the base libraries. - 1. Add files to the `base/` directory, and tests into `test/`. Often, this may not be necessary and you may be able to add your code to an existing file in `base/`. +Add new code to Julia's base libraries as follows: - 2. Add any new files to `sysimg.jl` in order to build them into the Julia system image and export necessary symbols in `exports.jl`. + 1. Edit the appropriate file in the `base/` directory, or add new files if necessary. Create tests for your functionality and add them to files in the `test/` directory. If you're editing C or Scheme code, most likely it lives in `src/` or one of its subdirectories, although some aspects of julia's REPL initialization live in `ui/`. - 3. Include your tests in `test/Makefile` and `test/runtests.jl`. + 2. Add any new files to `sysimg.jl` in order to build them into the Julia system image. + + 3. Add any necessary export symbols in `exports.jl`. + + 4. Include your tests in `test/Makefile` and `test/runtests.jl`. Build as usual, and do `make clean testall` to test your contribution. If your contribution includes changes to Makefiles or external dependencies, make sure you can build Julia from a clean tree using `git clean -fdx` or equivalent (be careful – this command will delete any files lying around that aren't checked into git). Make sure that [Travis](http://www.travis-ci.org) greenlights the pull request with a `Good to merge` message. diff --git a/Make.inc b/Make.inc index c7bbe0139f92a..5112d25cb622e 100644 --- a/Make.inc +++ b/Make.inc @@ -693,7 +693,7 @@ else #USEMSVC OSLIBS += kernel32.lib ws2_32.lib psapi.lib advapi32.lib iphlpapi.lib shell32.lib winmm.lib JLDFLAGS = -stack:8388608 endif -JCPPFLAGS += -D_WIN32_WINNT=0x0600 +JCPPFLAGS += -D_WIN32_WINNT=0x0502 UNTRUSTED_SYSTEM_LIBM = 1 endif diff --git a/Makefile b/Makefile index e53d146647c9d..aaaabf3909c33 100644 --- a/Makefile +++ b/Makefile @@ -67,7 +67,7 @@ release-candidate: release test @$(MAKE) -C doc helpdb.jl #Rebuild Julia online documentation for help(), apropos(), etc... @# Check to see if the above make invocations changed anything important - @if [ -n "$(git status --porcelain)" ]; then \ + @if [ -n "$$(git status --porcelain)" ]; then \ echo "Git repository dirty; Verify and commit changes to the repository, then retry"; \ exit 1; \ fi diff --git a/README.md b/README.md index b6305390aa6cd..0662c6f6fe9ca 100644 --- a/README.md +++ b/README.md @@ -378,7 +378,7 @@ Now you should be able to run Julia like this: julia -On Windows, double-click `julia.bat`. +On Windows, double-click `usr/bin/julia.exe`. If everything works correctly, you will see a Julia banner and an interactive prompt into which you can enter expressions for evaluation. You can read about [getting started](http://julialang.org/manual/getting-started) in the manual. diff --git a/README.windows.md b/README.windows.md index c410efc8de9e4..5363d266acd63 100644 --- a/README.windows.md +++ b/README.windows.md @@ -47,11 +47,11 @@ or edit `%USERPROFILE%\.gitconfig` and add/edit the lines: # Source distribution ## Supported build platforms - +- Windows 10: supported (32 and 64 bits) - Windows 8: supported (32 and 64 bits) - Windows 7: supported (32 and 64 bits) -- Windows Vista: unknown -- Windows XP: not supported (however, there have been some reports of success following the msys2 steps) +- Windows Vista: not officially supported (but probably works anyways) +- Windows XP: not officially supported (but may work anyways) ## Compiling with MinGW/MSYS2 @@ -198,16 +198,10 @@ Julia can be also compiled from source in [Cygwin](http://www.cygwin.com), using make -j 4 # Adjust the number of cores (4) to match your build environment. ``` -7. Run Julia with _either_ of: - - Using `make` - ``` - make run-julia - ``` - (the full syntax is `make run-julia[-release|-debug]`) - - - Using the Julia executables directly +7. Run Julia using the Julia executables directly ``` - usr/bin/julia + usr/bin/julia.exe + usr/bin/julia-debug.exe ``` ## Cross-compiling from Unix diff --git a/base/LineEdit.jl b/base/LineEdit.jl index 4ed1005fdbd57..0fb95c1908133 100644 --- a/base/LineEdit.jl +++ b/base/LineEdit.jl @@ -659,6 +659,8 @@ function write_prompt(terminal, p::Prompt) end write_prompt(terminal, s::ASCIIString) = write(terminal, s) +### Keymap Support + normalize_key(key::Char) = string(key) normalize_key(key::Integer) = normalize_key(char(key)) function normalize_key(key::AbstractString) @@ -673,16 +675,16 @@ function normalize_key(key::AbstractString) c, i = next(key, i) write(buf, uppercase(c)-64) elseif c == '\\' - c, i == next(key, i) + c, i = next(key, i) if c == 'C' - c, i == next(key, i) + c, i = next(key, i) @assert c == '-' - c, i == next(key, i) + c, i = next(key, i) write(buf, uppercase(c)-64) elseif c == 'M' - c, i == next(key, i) + c, i = next(key, i) @assert c == '-' - c, i == next(key, i) + c, i = next(key, i) write(buf, '\e') write(buf, c) end @@ -694,16 +696,31 @@ function normalize_key(key::AbstractString) end function normalize_keys(keymap::Dict) - return [normalize_key(k) => v for (k,v) in keymap] + ret = Dict{Any,Any}() + for (k,v) in keymap + normalized = normalize_key(k) + if haskey(ret,normalized) + error("""Multiple spellings of a key in a single keymap + (\"$k\" conflicts with existing mapping)""") + end + ret[normalized] = v + end + return ret end -function add_nested_key!(keymap::Dict, key, value) +function add_nested_key!(keymap::Dict, key, value; override = false) i = start(key) while !done(key, i) c, i = next(key, i) if c in keys(keymap) - if !isa(keymap[c], Dict) - error("Conflicting Definitions for keyseq " * escape_string(key) * " within one keymap") + if done(key, i) && override + # isa(keymap[c], Dict) - In this case we're overriding a prefix of an existing command + keymap[c] = value + break + else + if !isa(keymap[c], Dict) + error("Conflicting definitions for keyseq " * escape_string(key) * " within one keymap") + end end elseif done(key, i) keymap[c] = value @@ -715,36 +732,26 @@ function add_nested_key!(keymap::Dict, key, value) end end -# Turn a Dict{Any,Any} into a Dict{Char,Any} -# For now we use \0 to represent unknown chars so that they are sorted before everything else -# If we ever actually want to match \0 in input, this will have to be reworked -function normalize_keymap(keymap::Dict) - ret = Dict{Char,Any}() - direct_keys = filter((k,v) -> isa(v, Union(Function, Void)), keymap) - # first direct entries - for key in keys(direct_keys) - add_nested_key!(ret, key, keymap[key]) - end - # then redirected entries - for key in setdiff(keys(keymap), keys(direct_keys)) - value = normalize_key(keymap[key]) - haskey(keymap, value) || error("Could not find redirected value " * escape_string(keymap[key])) - add_nested_key!(ret, key, keymap[value]) - end - ret +# Redirect a key as if `seq` had been the keysequence instead in a lazy fashion. +# This is different from the default eager redirect, which only looks at the current and lower +# layers of the stack. +immutable KeyAlias + seq::ASCIIString + KeyAlias(seq) = new(normalize_key(seq)) end -match_input(k::Function, s, term, cs) = (update_key_repeats(s, cs); return keymap_fcn(k, s, ByteString(cs))) -match_input(k::Void, s, term, cs) = (s,p) -> return :ok -function match_input(keymap::Dict, s, term=terminal(s), cs=Char[]) +match_input(k::Function, s, term, cs, keymap) = (update_key_repeats(s, cs); return keymap_fcn(k, s, ByteString(cs))) +match_input(k::Void, s, term, cs, keymap) = (s,p) -> return :ok +match_input(k::KeyAlias, s, term, cs, keymap) = match_input(keymap, s, IOBuffer(k.seq), Char[], keymap) +function match_input(k::Dict, s, term=terminal(s), cs=Char[], keymap = k) # if we run out of characters to match before resolving an action, # return an empty keymap function eof(term) && return keymap_fcn(nothing, s, "") c = read(term, Char) push!(cs, c) - k = haskey(keymap, c) ? c : '\0' + key = haskey(k, c) ? c : '\0' # if we don't match on the key, look for a default action then fallback on 'nothing' to ignore - return match_input(get(keymap, k, nothing), s, term, cs) + return match_input(get(k, key, nothing), s, term, cs, keymap) end keymap_fcn(f::Void, s, c) = (s, p) -> return :ok @@ -766,6 +773,42 @@ function update_key_repeats(s::MIState, keystroke) return end + +## Conflict fixing +# Consider a keymap of the form +# +# { +# "**" => f +# "ab" => g +# } +# +# Naively this is transformed into a tree as +# +# { +# '*' => { +# '*' => f +# } +# 'a' => { +# 'b' => g +# } +# } +# +# However, that's not what we want, because now "ac" is +# is not defined. We need to fix this up and turn it into +# +# { +# '*' => { +# '*' => f +# } +# 'a' => { +# '*' => f +# 'b' => g +# } +# } +# +# i.e. copy over the appropraite default subdict +# + # deep merge where target has higher precedence function keymap_merge!(target::Dict, source::Dict) for k in keys(source) @@ -781,7 +824,7 @@ end fixup_keymaps!(d, l, s, sk) = nothing function fixup_keymaps!(dict::Dict, level, s, subkeymap) - if level > 1 + if level > 0 for d in values(dict) fixup_keymaps!(d, level-1, s, subkeymap) end @@ -799,6 +842,8 @@ end function add_specialisations(dict, subdict, level) default_branch = subdict['\0'] if isa(default_branch, Dict) + # Go through all the keymaps in the default branch + # and copy them over to dict for s in keys(default_branch) s == '\0' && add_specialisations(dict, default_branch, level+1) fixup_keymaps!(dict, level, s, default_branch[s]) @@ -806,42 +851,96 @@ function add_specialisations(dict, subdict, level) end end -fix_conflicts!(x) = fix_conflicts!(x, 1) -fix_conflicts!(others, level) = nothing -function fix_conflicts!(dict::Dict, level) +postprocess!(others) = nothing +function postprocess!(dict::Dict) # needs to be done first for every branch if haskey(dict, '\0') - add_specialisations(dict, dict, level) + add_specialisations(dict, dict, 1) + else + dict['\0'] = (args...)->error("Unrecognized input") end for (k,v) in dict k == '\0' && continue - fix_conflicts!(v, level+1) + postprocess!(v) + end +end + +function getEntry(keymap,key) + v = keymap + for c in key + if !haskey(v,c) + return nothing + end + v = v[c] end + return v end -function keymap_prepare(keymap::Dict) - if !haskey(keymap, "\0") - keymap["\0"] = (o...)->error("Unrecognized input") +# `target` is the total keymap being built up, already being a nested tree of Dicts. +# source is the keymap specified by the user (with normalized keys) +function keymap_merge(target,source) + ret = copy(target) + direct_keys = filter((k,v) -> isa(v, Union(Function, KeyAlias, Void)), source) + # first direct entries + for key in keys(direct_keys) + add_nested_key!(ret, key, source[key]; override = true) + end + # then redirected entries + for key in setdiff(keys(source), keys(direct_keys)) + # We first resolve redirects in the source + value = source[key] + visited = Array(Any,0) + while isa(value, Union(Char,AbstractString)) + value = normalize_key(value) + if value in visited + error("Eager redirection cycle detected for key " * escape_string(key)) + end + push!(visited,value) + if !haskey(source,value) + break + end + value = source[value] + end + + if isa(value, Union(Char,AbstractString)) + value = getEntry(ret, value) + if value === nothing + error("Could not find redirected value " * escape_string(source[key])) + end + end + add_nested_key!(ret, key, value; override = true) end - keymap = normalize_keymap(keymap) - fix_conflicts!(keymap) - keymap + ret end function keymap_unify(keymaps) - length(keymaps) == 1 && return keymaps[1] ret = Dict{Char,Any}() for keymap in keymaps - keymap_merge!(ret, keymap) + ret = keymap_merge(ret, keymap) end - fix_conflicts!(ret) + postprocess!(ret) return ret end +function validate_keymap(keymap) + for key in keys(keymap) + visited_keys = Any[key] + v = getEntry(keymap,key) + while isa(v,KeyAlias) + if v.seq in visited_keys + error("Alias cycle detected in keymap") + end + push!(visited_keys,v.seq) + v = getEntry(keymap,v.seq) + end + end +end + function keymap{D<:Dict}(keymaps::Array{D}) # keymaps is a vector of prioritized keymaps, with highest priority first - dict = map(normalize_keys, keymaps) - return keymap_prepare(merge(reverse(dict)...)) + ret = keymap_unify(map(normalize_keys, reverse(keymaps))) + validate_keymap(ret) + ret end const escape_defaults = merge!( @@ -857,16 +956,18 @@ const escape_defaults = merge!( "\e[4**" => nothing, "\e[5**" => nothing, "\e[6**" => nothing, - "\e[1~" => "\e[H", - "\e[4~" => "\e[F", - "\e[7~" => "\e[H", - "\e[8~" => "\e[F", - "\eOA" => "\e[A", - "\eOB" => "\e[B", - "\eOC" => "\e[C", - "\eOD" => "\e[D", - "\eOH" => "\e[H", - "\eOF" => "\e[F", + # These are different spellings of arrow keys, home keys, etc. + # and should always do the same as the canonical key sequence + "\e[1~" => KeyAlias("\e[H"), + "\e[4~" => KeyAlias("\e[F"), + "\e[7~" => KeyAlias("\e[H"), + "\e[8~" => KeyAlias("\e[F"), + "\eOA" => KeyAlias("\e[A"), + "\eOB" => KeyAlias("\e[B"), + "\eOC" => KeyAlias("\e[C"), + "\eOD" => KeyAlias("\e[D"), + "\eOH" => KeyAlias("\e[H"), + "\eOF" => KeyAlias("\e[F"), )) function write_response_buffer(s::PromptState, data) @@ -1074,7 +1175,7 @@ function setup_search_keymap(hp) # Backspace/^H '\b' => (s,data,c)->(edit_backspace(data.query_buffer) ? update_display_buffer(s, data) : beep(terminal(s))), - 127 => '\b', + 127 => KeyAlias('\b'), # Meta Backspace "\e\b" => (s,data,c)->(edit_delete_prev_word(data.query_buffer) ? update_display_buffer(s, data) : beep(terminal(s))), @@ -1215,10 +1316,10 @@ AnyDict( edit_insert(s, '\n') end end, - '\n' => '\r', + '\n' => KeyAlias('\r'), # Backspace/^H '\b' => (s,o...)->edit_backspace(s), - 127 => '\b', + 127 => KeyAlias('\b'), # Meta Backspace "\e\b" => (s,o...)->edit_delete_prev_word(s), "\e\x7f" => "\e\b", @@ -1315,7 +1416,8 @@ const prefix_history_keymap = AnyDict( "*" => (s,data,c)->begin accept_result(s, data.histprompt); ps = state(s, mode(s)) - match_input(keymap(ps, mode(s)), s, IOBuffer(c))(s, keymap_data(ps, mode(s))) + map = keymap(ps, mode(s)) + match_input(map, s, IOBuffer(c))(s, keymap_data(ps, mode(s))) end, # match escape sequences for pass thru "\e*" => "*", @@ -1450,7 +1552,8 @@ function prompt!(term, prompt, s = init_state(term, prompt)) start_reading(term) activate(prompt, s, term) while true - state = match_input(keymap(s, prompt), s)(s, keymap_data(s, prompt)) + map = keymap(s, prompt) + state = match_input(map, s)(s, keymap_data(s, prompt)) if state == :abort stop_reading(term) return buffer(s), false, false diff --git a/base/REPL.jl b/base/REPL.jl index 2c6aeee6b192c..42b9a2c67ce42 100644 --- a/base/REPL.jl +++ b/base/REPL.jl @@ -472,9 +472,9 @@ end function history_move_prefix(s::LineEdit.PrefixSearchState, hist::REPLHistoryProvider, prefix::AbstractString, - backwards::Bool) + backwards::Bool, + cur_idx = hist.cur_idx) cur_response = bytestring(LineEdit.buffer(s)) - cur_idx = hist.cur_idx # when searching forward, start at last_idx if !backwards && hist.last_idx > 0 cur_idx = hist.last_idx @@ -484,16 +484,20 @@ function history_move_prefix(s::LineEdit.PrefixSearchState, idxs = backwards ? ((cur_idx-1):-1:1) : ((cur_idx+1):max_idx) for idx in idxs if (idx == max_idx) || (beginswith(hist.history[idx], prefix) && (hist.history[idx] != cur_response || hist.modes[idx] != LineEdit.mode(s))) - history_move(s, hist, idx) - if length(prefix) == 0 - # on empty prefix search, move cursor to the end - LineEdit.move_input_end(s) - else - # otherwise, keep cursor at the prefix position as a visual cue - seek(LineEdit.buffer(s), length(prefix)) + m = history_move(s, hist, idx) + if m == :ok + if length(prefix) == 0 + # on empty prefix search, move cursor to the end + LineEdit.move_input_end(s) + else + # otherwise, keep cursor at the prefix position as a visual cue + seek(LineEdit.buffer(s), length(prefix)) + end + LineEdit.refresh_line(s) + return :ok + elseif m == :skip + return history_move_prefix(s,hist,prefix,backwards,idx) end - LineEdit.refresh_line(s) - return :ok end end Terminals.beep(LineEdit.terminal(s)) @@ -608,6 +612,28 @@ function reset(repl::LineEditREPL) print(repl.t,Base.text_colors[:normal]) end +function mode_keymap(julia_prompt) + AnyDict( + '\b' => function (s,o...) + if isempty(s) || position(LineEdit.buffer(s)) == 0 + buf = copy(LineEdit.buffer(s)) + transition(s, julia_prompt) + LineEdit.state(s, julia_prompt).input_buffer = buf + LineEdit.refresh_line(s) + else + LineEdit.edit_backspace(s) + end + end, + "^C" => function (s,o...) + LineEdit.move_input_end(s) + LineEdit.refresh_line(s) + print(LineEdit.terminal(s), "^C\n\n") + transition(s, julia_prompt) + transition(s, :reset) + LineEdit.refresh_line(s) + end) +end + function setup_interface(repl::LineEditREPL; hascolor = repl.hascolor, extra_repl_keymap = Dict{Any,Any}[]) ### # @@ -788,28 +814,9 @@ function setup_interface(repl::LineEditREPL; hascolor = repl.hascolor, extra_rep julia_prompt.keymap_dict = LineEdit.keymap(a) - const mode_keymap = AnyDict( - '\b' => function (s,o...) - if isempty(s) || position(LineEdit.buffer(s)) == 0 - buf = copy(LineEdit.buffer(s)) - transition(s, julia_prompt) - LineEdit.state(s, julia_prompt).input_buffer = buf - LineEdit.refresh_line(s) - else - LineEdit.edit_backspace(s) - end - end, - "^C" => function (s,o...) - LineEdit.move_input_end(s) - LineEdit.refresh_line(s) - print(LineEdit.terminal(s), "^C\n\n") - transition(s, julia_prompt) - transition(s, :reset) - LineEdit.refresh_line(s) - end - ) + mk = mode_keymap(julia_prompt) - b = Dict{Any,Any}[skeymap, mode_keymap, prefix_keymap, LineEdit.history_keymap, LineEdit.default_keymap, LineEdit.escape_defaults] + b = Dict{Any,Any}[skeymap, mk, prefix_keymap, LineEdit.history_keymap, LineEdit.default_keymap, LineEdit.escape_defaults] prepend!(b, extra_repl_keymap) shell_mode.keymap_dict = help_mode.keymap_dict = LineEdit.keymap(b) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 495d6a4174ff9..dc09300dfcbc3 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -26,6 +26,8 @@ endof(a::AbstractArray) = length(a) first(a::AbstractArray) = a[1] first(a) = next(a,start(a))[1] last(a) = a[end] +ctranspose(a::AbstractArray) = error("ctranspose not implemented for $(typeof(a)). Consider adding parentheses, e.g. A*(B*C') instead of A*B*C' to avoid explicit calculation of the transposed matrix.") +transpose(a::AbstractArray) = error("transpose not implemented for $(typeof(a)). Consider adding parentheses, e.g. A*(B*C.') instead of A*B*C' to avoid explicit calculation of the transposed matrix.") function stride(a::AbstractArray, i::Integer) if i > ndims(a) diff --git a/base/base.jl b/base/base.jl index 8b79077e26929..8ba2c3a931487 100644 --- a/base/base.jl +++ b/base/base.jl @@ -117,6 +117,10 @@ type DimensionMismatch <: Exception end DimensionMismatch() = DimensionMismatch("") +# For passing constants through type inference +immutable Val{T} +end + type WeakRef value WeakRef() = WeakRef(nothing) diff --git a/base/base64.jl b/base/base64.jl index 9220c4c112a8b..a736b9e9a1b1e 100644 --- a/base/base64.jl +++ b/base/base64.jl @@ -1,25 +1,25 @@ module Base64 -import Base: read, write, close -export Base64Pipe, base64 +import Base: read, write, close, eof, empty! +export Base64EncodePipe, Base64DecodePipe, base64encode, base64decode -# Base64Pipe is a pipe-like IO object, which converts writes (and -# someday reads?) into base64 encoded (decoded) data send to a stream. -# (You must close the pipe to complete the encode, separate from -# closing the target stream). We also have a function base64(f, +# Base64EncodePipe is a pipe-like IO object, which converts into base64 data sent +# to a stream. (You must close the pipe to complete the encode, separate from +# closing the target stream). We also have a function base64encode(f, # args...) which works like sprint except that it produces -# base64-encoded data, along with base64(args...) which is equivalent -# to base64(write, args...), to return base64 strings. - +# base64-encoded data, along with base64encode(args...) which is equivalent +# to base64encode(write, args...), to return base64 strings. +# A Base64DecodePipe object can be used to decode base64-encoded data read from a stream +# , while function base64decode is useful for decoding strings ############################################################################# -type Base64Pipe <: IO +type Base64EncodePipe <: IO io::IO # writing works in groups of 3, so we need to cache last two bytes written b0::UInt8 b1::UInt8 nb::UInt8 # number of bytes in cache: 0, 1, or 2 - function Base64Pipe(io::IO) + function Base64EncodePipe(io::IO) b = new(io,0,0,0) finalizer(b, close) return b @@ -32,6 +32,8 @@ end const b64chars = ['A':'Z','a':'z','0':'9','+','/'] +const base64_pad = uint8('=') + function b64(x::UInt8, y::UInt8, z::UInt8) n = int(x)<<16 | int(y)<<8 | int(z) b64chars[(n >> 18) + 1], @@ -42,17 +44,46 @@ end function b64(x::UInt8, y::UInt8) a, b, c = b64(x, y, 0x0) - a, b, c, '=' + a, b, c, base64_pad end function b64(x::UInt8) a, b = b64(x, 0x0, 0x0) - a, b, '=', '=' + a, b, base64_pad, base64_pad +end + +const sentinel = typemax(UInt8) +const revb64chars = fill(sentinel, 256) +# Fill revb64chars +for (val, ch) in enumerate(b64chars) + revb64chars[uint8(ch)] = uint8(val - 1) end +#Decode a block of at least 2 and at most 4 bytes, received in encvec +#Returns the first decoded byte and stores up to two more in cache +function b64decode!(encvec::Vector{UInt8}, cache::Vector{UInt8}) + if length(encvec) < 2 + error("Incorrect base64 format") + end + @inbounds u = revb64chars[encvec[1]] + @inbounds v = revb64chars[encvec[2]] + empty!(cache) + res = (u << 2) | (v >> 4) + if length(encvec) > 2 + @inbounds w = revb64chars[encvec[3]] + push!(cache, (v << 4) | (w >> 2)) + end + if length(encvec) > 3 + @inbounds z = revb64chars[encvec[4]] + push!(cache, (w << 6) | z) + end + res +end + + ############################################################################# -function write(b::Base64Pipe, x::AbstractVector{UInt8}) +function write(b::Base64EncodePipe, x::AbstractVector{UInt8}) n = length(x) s = 1 # starting index # finish any cached data to write: @@ -93,7 +124,7 @@ function write(b::Base64Pipe, x::AbstractVector{UInt8}) end end -function write(b::Base64Pipe, x::UInt8) +function write(b::Base64EncodePipe, x::UInt8) if b.nb == 0 b.b0 = x b.nb = 1 @@ -106,7 +137,7 @@ function write(b::Base64Pipe, x::UInt8) end end -function close(b::Base64Pipe) +function close(b::Base64EncodePipe) if b.nb > 0 # write leftover bytes + padding if b.nb == 1 @@ -119,14 +150,14 @@ function close(b::Base64Pipe) end # like sprint, but returns base64 string -function base64(f::Function, args...) +function base64encode(f::Function, args...) s = IOBuffer() - b = Base64Pipe(s) + b = Base64EncodePipe(s) f(b, args...) close(b) takebuf_string(s) end -base64(x...) = base64(write, x...) +base64encode(x...) = base64encode(write, x...) ############################################################################# @@ -134,4 +165,48 @@ base64(x...) = base64(write, x...) ############################################################################# +type Base64DecodePipe <: IO + io::IO + # reading works in blocks of 4 characters that are decoded into 3 bytes and 2 of them cached + cache::Vector{UInt8} + encvec::Vector{UInt8} + + function Base64DecodePipe(io::IO) + b = new(io,[],[]) + finalizer(b, close) + return b + end +end + +function read(b::Base64DecodePipe, t::Type{UInt8}) + if length(b.cache) > 0 + val = shift!(b.cache) + else + empty!(b.encvec) + while !eof(b.io) && length(b.encvec) < 4 + c::UInt8 = read(b.io, t) + @inbounds if revb64chars[c] != sentinel + push!(b.encvec, c) + end + end + val = b64decode!(b.encvec,b.cache) + end + val +end + +function eof(b::Base64DecodePipe) + return length(b.cache) == 0 && eof(b.io) +end + +function close(b::Base64DecodePipe) +end + +# Decodes a base64-encoded string +function base64decode(s) + b = IOBuffer(s) + decoded = readall(Base64DecodePipe(b)) + close(b) + decoded +end + end # module diff --git a/base/deprecated.jl b/base/deprecated.jl index f8b063704ed17..1904a0d267bf3 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -177,7 +177,7 @@ scale!{T<:Base.LinAlg.BlasReal}(X::Array{T}, s::Complex) = error("scale!: Cannot @deprecate rsplit(x,y,l::Integer) rsplit(x,y;limit=l) @deprecate rsplit(x,y,k::Bool) rsplit(x,y;keep=k) -export TcpSocket, UdpSocket, IpAddr +export UdpSocket const TcpSocket = TCPSocket const UdpSocket = UDPSocket const IpAddr = IPAddr @@ -246,6 +246,10 @@ const Uint128 = UInt128 @deprecate iround(x) round(Integer,x) @deprecate iround{T}(::Type{T},x) round(T,x) +export Base64Pipe, base64 +const Base64Pipe = Base64EncodePipe +const base64 = base64encode + @deprecate prevind(a::Any, i::Integer) i-1 @deprecate nextind(a::Any, i::Integer) i+1 @@ -254,3 +258,4 @@ const Uint128 = UInt128 @deprecate squeeze(X, dims) squeeze(X, tuple(dims...)) @deprecate sizehint(A, n) sizehint!(A, n) + diff --git a/base/dict.jl b/base/dict.jl index b5c5153cebc6c..a5135652694dd 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -54,7 +54,7 @@ function _truncate_at_width_or_chars(str, width, chars="", truncmark="…") lastidx != 0 && str[lastidx] in chars && (lastidx = prevind(str, lastidx)) truncidx == 0 && (truncidx = lastidx) - if lastidx < sizeof(str) + if lastidx < endof(str) return bytestring(SubString(str, 1, truncidx) * truncmark) else return bytestring(str) diff --git a/base/exports.jl b/base/exports.jl index 5976ac5e9f64c..fad5574341d0f 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -113,6 +113,7 @@ export UnitRange, UTF16String, UTF32String, + Val, VecOrMat, Vector, VersionNumber, @@ -806,8 +807,10 @@ export # strings and text output ascii, base, - base64, - Base64Pipe, + base64encode, + base64decode, + Base64EncodePipe, + Base64DecodePipe, beginswith, bin, bits, @@ -1068,6 +1071,7 @@ export current_module, edit, code_typed, + code_warntype, code_lowered, code_llvm, code_native, @@ -1374,6 +1378,7 @@ export @edit, @less, @code_typed, + @code_warntype, @code_lowered, @code_llvm, @code_native, diff --git a/base/inference.jl b/base/inference.jl index 8d1751244e434..cbe4666f0717a 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -34,6 +34,26 @@ end inference_stack = EmptyCallStack() +# Julia compiler options struct (see jl_compileropts_t in src/julia.h) +immutable JLCompilerOpts + julia_home::Ptr{Cchar} + julia_bin::Ptr{Cchar} + build_path::Ptr{Cchar} + image_file::Ptr{Cchar} + cpu_target::Ptr{Cchar} + code_coverage::Int8 + malloc_log::Int8 + check_bounds::Int8 + dumpbitcode::Int8 + int_literals::Cint + compile_enabled::Int8 + opt_level::Int8 + depwarn::Int8 + can_inline::Int8 +end + +compileropts() = unsafe_load(cglobal(:jl_compileropts, JLCompilerOpts)) + function is_static_parameter(sv::StaticVarInfo, s::Symbol) sp = sv.sp for i=1:2:length(sp) @@ -1369,9 +1389,27 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop) end end end - for i=1:la - s[1][args[i]] = atypes[i] + + laty = length(atypes) + if laty > 0 + lastatype = atypes[laty] + if isvarargtype(lastatype) + lastatype = lastatype.parameters[1] + laty -= 1 + end + if laty > la + laty = la + end + for i=1:laty + s[1][args[i]] = atypes[i] + end + for i=laty+1:la + s[1][args[i]] = lastatype + end + else + @assert la == 0 end + # types of closed vars cenv = ObjectIdDict() for vi = ((ast.args[2][3])::Array{Any,1}) @@ -1554,9 +1592,11 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop) if !rec @assert fulltree.args[3].head === :body - fulltree.args[3] = inlining_pass(fulltree.args[3], sv, fulltree)[1] - # inlining can add variables - sv.vars = append_any(f_argnames(fulltree), fulltree.args[2][1]) + if compileropts().can_inline == 1 + fulltree.args[3] = inlining_pass(fulltree.args[3], sv, fulltree)[1] + # inlining can add variables + sv.vars = append_any(f_argnames(fulltree), fulltree.args[2][1]) + end tuple_elim_pass(fulltree) tupleref_elim_pass(fulltree.args[3], sv) linfo.inferred = true @@ -2329,7 +2369,7 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast) else methitype = methargs[end] if isvarargtype(methitype) - methitype = (methitype::Vararg).parameters[1] + methitype = methitype.parameters[1] else @assert i==nm end diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 390bea3bd761f..9e3cb9a8024c3 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -27,7 +27,7 @@ function edit(file::AbstractString, line::Integer) no_line_msg = "Unknown editor: no line number information passed.\nThe method is defined at line $line." if beginswith(edname, "emacs") || edname == "gedit" spawn(`$edpath +$line $file`) - elseif edname == "vim" || edname == "nano" + elseif edname == "vim" || edname == "nvim" || edname == "nano" run(`$edpath +$line $file`) elseif edname == "textmate" || edname == "mate" || edname == "kate" spawn(`$edpath $file -l $line`) @@ -203,6 +203,30 @@ function which(f, t::(Type...)) ms[1] end +# displaying type-ambiguity warnings + +function code_warntype(io::IO, f, t::(Type...)) + global show_expr_type_emphasize + state = show_expr_type_emphasize::Bool + ct = code_typed(f, t) + show_expr_type_emphasize::Bool = true + for ast in ct + println(io, "Variables:") + vars = ast.args[2][2] + for v in vars + print(io, " ", v[1]) + show_expr_type(io, v[2]) + print(io, '\n') + end + print(io, "\nBody:\n ") + show_unquoted(io, ast.args[3], 2) + print(io, '\n') + end + show_expr_type_emphasize::Bool = false + nothing +end +code_warntype(f, t::(Type...)) = code_warntype(STDOUT, f, t) + typesof(args...) = map(a->(isa(a,Type) ? Type{a} : typeof(a)), args) function gen_call_with_extracted_types(fcn, ex0) @@ -248,7 +272,7 @@ function gen_call_with_extracted_types(fcn, ex0) exret end -for fname in [:which, :less, :edit, :code_typed, :code_lowered, :code_llvm, :code_native] +for fname in [:which, :less, :edit, :code_typed, :code_warntype, :code_lowered, :code_llvm, :code_native] @eval begin macro ($fname)(ex0) gen_call_with_extracted_types($(Expr(:quote,fname)), ex0) @@ -375,7 +399,7 @@ function runtests(tests = ["all"], numcores = ceil(Int,CPU_CORES/2)) ENV2 = copy(ENV) ENV2["JULIA_CPU_CORES"] = "$numcores" try - run(setenv(`$(joinpath(JULIA_HOME, "julia")) $(joinpath(JULIA_HOME, + run(setenv(`$(julia_cmd()) $(joinpath(JULIA_HOME, Base.DATAROOTDIR, "julia", "test", "runtests.jl")) $tests`, ENV2)) catch buf = PipeBuffer() diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index aa16df179b3dd..4ee7e30e17c4e 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -90,7 +90,7 @@ function cholfact(x::Number, uplo::Symbol=:U) Cholesky(xf, uplo) end -chol(A::AbstractMatrix, uplo::Symbol=:U) = chol!(copy(A), uplo) +chol{T}(A::AbstractMatrix{T}, uplo::Symbol=:U) = (S = promote_type(typeof(chol(one(T))),Float32); S != T ? chol!(convert(AbstractMatrix{S}, A), uplo) : chol!(copy(A), uplo)) function chol!(x::Number, uplo::Symbol=:U) rx = real(x) rx == abs(x) || throw(DomainError()) diff --git a/base/linalg/factorization.jl b/base/linalg/factorization.jl index 4d074c2c16a22..4d2c745c3363d 100644 --- a/base/linalg/factorization.jl +++ b/base/linalg/factorization.jl @@ -3,6 +3,8 @@ abstract Factorization{T} eltype{T}(F::Factorization{T}) = T +transpose(F::Factorization) = error("transpose not implemented for $(typeof(F))") +ctranspose(F::Factorization) = error("ctranspose not implemented for $(typeof(F))") macro assertposdef(A, info) :(($info)==0 ? $A : throw(PosDefException($info))) diff --git a/base/linalg/givens.jl b/base/linalg/givens.jl index f8e17b3a490ca..969d2898f9e05 100644 --- a/base/linalg/givens.jl +++ b/base/linalg/givens.jl @@ -1,14 +1,35 @@ -immutable Givens{T} +abstract AbstractRotation{T} + +transpose(R::AbstractRotation) = error("transpose not implemented for $(typeof(R)). Consider using conjugate transpose (') instead of transpose (.').") + +function *{T,S}(R::AbstractRotation{T}, A::AbstractMatrix{S}) + TS = typeof(zero(T)*zero(S) + zero(T)*zero(S)) + A_mul_B!(convert(AbstractRotation{TS}, R), TS == S ? copy(A) : convert(AbstractArray{TS}, A)) +end +function A_mul_Bc{T,S}(A::AbstractMatrix{T}, R::AbstractRotation{S}) + TS = typeof(zero(T)*zero(S) + zero(T)*zero(S)) + A_mul_Bc!(TS == T ? copy(A) : convert(AbstractArray{TS}, A), convert(AbstractRotation{TS}, R)) +end + +immutable Givens{T} <: AbstractRotation{T} i1::Int i2::Int c::T s::T - r::T end -type Rotation{T} - rotations::Vector{T} +type Rotation{T} <: AbstractRotation{T} + rotations::Vector{Givens{T}} end -typealias AbstractRotation Union(Givens, Rotation) + +convert{T}(::Type{Givens{T}}, G::Givens{T}) = G +convert{T}(::Type{Givens{T}}, G::Givens) = Givens(G.i1, G.i2, convert(T, G.c), convert(T, G.s)) +convert{T}(::Type{Rotation{T}}, R::Rotation{T}) = R +convert{T}(::Type{Rotation{T}}, R::Rotation) = Rotation{T}([convert(Givens{T}, g) for g in R.rotations]) +convert{T}(::Type{AbstractRotation{T}}, G::Givens) = convert(Givens{T}, G) +convert{T}(::Type{AbstractRotation{T}}, R::Rotation) = convert(Rotation{T}, R) + +ctranspose(G::Givens) = Givens(G.i1, G.i2, conj(G.c), -G.s) +ctranspose{T}(R::Rotation{T}) = Rotation{T}(reverse!([ctranspose(r) for r in R.rotations])) realmin2(::Type{Float32}) = reinterpret(Float32, 0x26000000) realmin2(::Type{Float64}) = reinterpret(Float64, 0x21a0000000000000) @@ -187,13 +208,13 @@ end function givens{T}(f::T, g::T, i1::Integer, i2::Integer) i1 < i2 || error("second index must be larger than the first") c, s, r = givensAlgorithm(f, g) - Givens(i1, i2, convert(T, c), convert(T, s), convert(T, r)) + Givens(i1, i2, convert(T, c), convert(T, s)), r end function givens{T}(A::AbstractMatrix{T}, i1::Integer, i2::Integer, col::Integer) i1 < i2 || error("second index must be larger than the first") c, s, r = givensAlgorithm(A[i1,col], A[i2,col]) - Givens(i1, i2, convert(T, c), convert(T, s), convert(T, r)) + Givens(i1, i2, convert(T, c), convert(T, s)), r end getindex(G::Givens, i::Integer, j::Integer) = i == j ? (i == G.i1 || i == G.i2 ? G.c : one(G.c)) : (i == G.i1 && j == G.i2 ? G.s : (i == G.i2 && j == G.i1 ? -G.s : zero(G.s))) @@ -236,6 +257,3 @@ function A_mul_Bc!(A::AbstractMatrix, R::Rotation) return A end *{T}(G1::Givens{T}, G2::Givens{T}) = Rotation(push!(push!(Givens{T}[], G2), G1)) -*(R::AbstractRotation, A::AbstractMatrix) = A_mul_B!(R, copy(A)) - -A_mul_Bc(A::AbstractMatrix, R::AbstractRotation) = A_mul_Bc!(copy(A), R) diff --git a/base/multi.jl b/base/multi.jl index c9a0abb1ddc40..6054a70e3fd8d 100644 --- a/base/multi.jl +++ b/base/multi.jl @@ -1031,8 +1031,8 @@ function start_cluster_workers(manager, params, resp_arr, launched_ntfy) if length(launched) > 0 wconfig = shift!(launched) rr = connect_n_create_worker(manager, get_next_pid(), wconfig) - let rr=rr - @async launch_additional(worker_from_id(fetch(rr)), resp_arr, launched_ntfy) + let rr=rr, exename = params[:exename] + @async launch_additional(worker_from_id(fetch(rr)), exename, resp_arr, launched_ntfy) end push!(resp_arr, rr) @@ -1044,16 +1044,18 @@ function start_cluster_workers(manager, params, resp_arr, launched_ntfy) notify(launched_ntfy) end -function launch_additional(w::Worker, resp_arr::Array, launched_ntfy::Condition) +function launch_additional(w::Worker, exename, resp_arr::Array, launched_ntfy::Condition) cnt = get(w.config.count, 1) if cnt == :auto cnt = get(w.config.environ)[:cpu_cores] end cnt = cnt - 1 # Removing self from the requested number + exeflags = get(w.config.exeflags, ``) + cmd = `$exename $exeflags` if cnt > 0 npids = [get_next_pid() for x in 1:cnt] - new_workers = remotecall_fetch(w.id, launch_additional, cnt, npids, get(w.config.exeflags, ``)) + new_workers = remotecall_fetch(w.id, launch_additional, cnt, npids, cmd) # keyword argument max_parallel is only relevant for concurrent ssh connections to a unique host # Post launch, ssh from master to workers is used only if tunnel is true @@ -1111,14 +1113,14 @@ function connect_n_create_worker(manager, pid, wconfig) end -function launch_additional(np::Integer, pids::Array, exeflags::Cmd) +function launch_additional(np::Integer, pids::Array, cmd::Cmd) assert(np == length(pids)) io_objs = cell(np) addresses = cell(np) for i in 1:np - io, pobj = open(detach(`$(JULIA_HOME)/$(exename()) $exeflags`), "r") + io, pobj = open(detach(cmd), "r") io_objs[i] = io end @@ -1214,7 +1216,7 @@ function launch(manager::LocalManager, params::Dict, launched::Array, c::Conditi exeflags = params[:exeflags] for i in 1:manager.np - io, pobj = open(detach(`$(dir)/$(exename) $exeflags --bind-to $(LPROC.bind_addr) --worker`), "r") + io, pobj = open(detach(setenv(`$(julia_cmd(exename)) $exeflags --bind-to $(LPROC.bind_addr) --worker`, dir=dir)), "r") wconfig = WorkerConfig() wconfig.process = pobj wconfig.io = io @@ -1489,11 +1491,9 @@ function addprocs(machines::AbstractVector; tunnel=false, sshflags=``, max_paral end default_addprocs_params() = AnyDict( - :dir=>JULIA_HOME, - :exename=>exename(), - :exeflags=>``) - -exename() = ccall(:jl_is_debugbuild,Cint,())==0 ? "./julia" : "./julia-debug" + :dir => pwd(), + :exename => joinpath(JULIA_HOME,julia_exename()), + :exeflags => ``) ## higher-level functions: spawn, pmap, pfor, etc. ## diff --git a/base/multimedia.jl b/base/multimedia.jl index 3c229436fe504..f513777d534ba 100644 --- a/base/multimedia.jl +++ b/base/multimedia.jl @@ -79,8 +79,8 @@ function reprmime(m::MIME, x) takebuf_array(s) end reprmime(m::MIME, x::Vector{UInt8}) = x -stringmime(m::MIME, x) = base64(writemime, m, x) -stringmime(m::MIME, x::Vector{UInt8}) = base64(write, x) +stringmime(m::MIME, x) = base64encode(writemime, m, x) +stringmime(m::MIME, x::Vector{UInt8}) = base64encode(write, x) # it is convenient to accept strings instead of ::MIME istext(m::AbstractString) = istext(MIME(m)) diff --git a/base/nullable.jl b/base/nullable.jl index 830677588efb7..050b5dd572a03 100644 --- a/base/nullable.jl +++ b/base/nullable.jl @@ -16,7 +16,7 @@ eltype{T}(::Type{Nullable{T}}) = T eltype{T}(x::Nullable{T}) = T function convert{T}(::Type{Nullable{T}}, x::Nullable) - return isnull(x) ? Nullable{T}() : Nullable(convert(T, get(x))) + return isnull(x) ? Nullable{T}() : Nullable{T}(convert(T, get(x))) end convert{T}(::Type{Nullable{T}}, x::T) = Nullable{T}(x) diff --git a/base/pointer.jl b/base/pointer.jl index e5556cafe6f29..d55a90794455e 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -60,6 +60,7 @@ eltype{T}(::Ptr{T}) = T ## limited pointer arithmetic & comparison ## ==(x::Ptr, y::Ptr) = uint(x) == uint(y) +isless(x::Ptr, y::Ptr) = isless(uint(x), uint(y)) -(x::Ptr, y::Ptr) = uint(x) - uint(y) +(x::Ptr, y::Integer) = oftype(x, (uint(x) + (y % UInt) % UInt)) diff --git a/base/precompile.jl b/base/precompile.jl index 277adf6669946..5992ae44abefb 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -64,7 +64,7 @@ precompile(Base.LineEdit.edit_move_right, (Base.LineEdit.PromptState,)) precompile(Base.LineEdit.edit_move_right, (IOBuffer,)) precompile(Base.LineEdit.edit_move_up, (Base.LineEdit.MIState,)) precompile(Base.LineEdit.edit_move_up, (IOBuffer,)) -precompile(Base.LineEdit.fix_conflicts!, (Void, Int)) +precompile(Base.LineEdit.postprocess!, (Void, Int)) precompile(Base.LineEdit.history_prev, (Base.LineEdit.MIState, Base.REPL.REPLHistoryProvider)) precompile(Base.LineEdit.history_prev, (Base.LineEdit.MIState, Base.REPL.REPLHistoryProvider, Int)) precompile(Base.LineEdit.init_state, (Base.Terminals.TTYTerminal, Base.LineEdit.HistoryPrompt{Base.REPL.REPLHistoryProvider})) diff --git a/base/random.jl b/base/random.jl index 905fd31abb9fe..3f08aac2be571 100644 --- a/base/random.jl +++ b/base/random.jl @@ -214,7 +214,7 @@ rand_ui10_raw(r::AbstractRNG) = rand(r, UInt16) rand_ui23_raw(r::AbstractRNG) = rand(r, UInt32) rand(r::Union(RandomDevice,MersenneTwister), ::Type{Float16}) = - Float16(reinterpret(Float32, rand_ui10_raw(r) % UInt32 & 0x007fe000 | 0x3f800000) - 1) + Float16(reinterpret(Float32, (rand_ui10_raw(r) % UInt32 << 13) & 0x007fe000 | 0x3f800000) - 1) rand(r::Union(RandomDevice,MersenneTwister), ::Type{Float32}) = reinterpret(Float32, rand_ui23_raw(r) % UInt32 & 0x007fffff | 0x3f800000) - 1 diff --git a/base/reflection.jl b/base/reflection.jl index ecbd86655fe43..3adb144cfdb02 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -155,8 +155,10 @@ function _dump_function(f, t::ANY, native, wrapper) str end -code_llvm (f::Function, types::(Type...)) = print(_dump_function(f, types, false, false)) -code_native(f::Function, types::(Type...)) = print(_dump_function(f, types, true, false)) +code_llvm(io::IO, f::Function, types::(Type...)) = print(io, _dump_function(f, types, false, false)) +code_llvm(f::Function, types::(Type...)) = code_llvm(STDOUT, f, types) +code_native(io::IO, f::Function, types::(Type...)) = print(io, _dump_function(f, types, true, false)) +code_native(f::Function, types::(Type...)) = code_native(STDOUT, f, types) function functionlocs(f::ANY, types=(Type...)) locs = Any[] diff --git a/base/regex.jl b/base/regex.jl index 4d6d4978b7984..485ac4d54ecfa 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -6,7 +6,7 @@ const DEFAULT_OPTS = PCRE.JAVASCRIPT_COMPAT | PCRE.UTF8 | PCRE.NO_UTF8_CHECK type Regex pattern::ByteString - options::UInt32 + options::Int32 regex::Ptr{Void} extra::Ptr{Void} ovec::Vector{Int32} @@ -113,7 +113,7 @@ function ismatch(r::Regex, s::SubString, offset::Integer=0) r.ovec) end -function match(re::Regex, str::UTF8String, idx::Integer, add_opts::UInt32=uint32(0)) +function match(re::Regex, str::UTF8String, idx::Integer, add_opts::Int32=int32(0)) opts = re.options & PCRE.EXECUTE_MASK | add_opts compile(re) if !PCRE.exec(re.regex, re.extra, str, idx-1, opts, re.ovec) @@ -127,7 +127,7 @@ function match(re::Regex, str::UTF8String, idx::Integer, add_opts::UInt32=uint32 RegexMatch(mat, cap, re.ovec[1]+1, off) end -match(re::Regex, str::Union(ByteString,SubString), idx::Integer, add_opts::UInt32=uint32(0)) = +match(re::Regex, str::Union(ByteString,SubString), idx::Integer, add_opts::Int32=int32(0)) = match(re, utf8(str), idx, add_opts) match(r::Regex, s::AbstractString) = match(r, s, start(s)) @@ -201,7 +201,7 @@ immutable RegexMatchIterator end compile(itr::RegexMatchIterator) = (compile(itr.regex); itr) eltype(itr::RegexMatchIterator) = RegexMatch -start(itr::RegexMatchIterator) = match(itr.regex, itr.string, 1, uint32(0)) +start(itr::RegexMatchIterator) = match(itr.regex, itr.string, 1, int32(0)) done(itr::RegexMatchIterator, prev_match) = (prev_match == nothing) # Assumes prev_match is not nothing @@ -218,10 +218,10 @@ function next(itr::RegexMatchIterator, prev_match) offset = prev_match.offset + endof(prev_match.match) end - opts_nonempty = uint32(PCRE.ANCHORED | PCRE.NOTEMPTY_ATSTART) + opts_nonempty = int32(PCRE.ANCHORED | PCRE.NOTEMPTY_ATSTART) while true mat = match(itr.regex, itr.string, offset, - prevempty ? opts_nonempty : uint32(0)) + prevempty ? opts_nonempty : int32(0)) if mat === nothing if prevempty && offset <= length(itr.string.data) diff --git a/base/show.jl b/base/show.jl index 6577b16f54d1c..0d88a4a8396bd 100644 --- a/base/show.jl +++ b/base/show.jl @@ -247,6 +247,7 @@ const uni_ops = Set{Symbol}([:(+), :(-), :(!), :(¬), :(~), :(<:), :(>:), :(√) const expr_infix_wide = Set([:(=), :(+=), :(-=), :(*=), :(/=), :(\=), :(&=), :(|=), :($=), :(>>>=), :(>>=), :(<<=), :(&&), :(||), :(<:), :(=>)]) const expr_infix = Set([:(:), :(->), symbol("::")]) +const expr_infix_any = union(expr_infix, expr_infix_wide) const expr_calls = Dict(:call =>('(',')'), :calldecl =>('(',')'), :ref =>('[',']'), :curly =>('{','}')) const expr_parens = Dict(:tuple=>('(',')'), :vcat=>('[',']'), :cell1d=>("Any[","]"), :hcat =>('[',']'), :row =>('[',']')) @@ -290,19 +291,26 @@ unquoted(ex::Expr) = ex.args[1] ## AST printing helpers ## const indent_width = 4 +show_expr_type_emphasize = false function show_expr_type(io::IO, ty) - if !is(ty, Any) - if is(ty, Function) - print(io, "::F") - elseif is(ty, IntrinsicFunction) - print(io, "::I") + if is(ty, Function) + print(io, "::F") + elseif is(ty, IntrinsicFunction) + print(io, "::I") + else + if show_expr_type_emphasize::Bool && !isleaftype(ty) + emphasize(io, "::$ty") else - print(io, "::$ty") + if !is(ty, Any) + print(io, "::$ty") + end end end end +emphasize(io, str::AbstractString) = have_color ? print_with_color(:red, io, str) : print(io, uppercase(str)) + show_linenumber(io::IO, line) = print(io," # line ",line,':') show_linenumber(io::IO, line, file) = print(io," # ",file,", line ",line,':') @@ -351,7 +359,8 @@ end # show a normal (non-operator) function call, e.g. f(x,y) or A[z] function show_call(io::IO, head, func, func_args, indent) op, cl = expr_calls[head] - if isa(func, Symbol) || (isa(func, Expr) && func.head == :.) + if isa(func, Symbol) || (isa(func, Expr) && + (func.head == :. || func.head == :curly)) show_unquoted(io, func, indent) else print(io, '(') @@ -409,6 +418,9 @@ end # TODO: implement interpolated strings function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) head, args, nargs = ex.head, ex.args, length(ex.args) + show_type = true + global show_expr_type_emphasize + state = show_expr_type_emphasize::Bool # dot (i.e. "x.y") if is(head, :(.)) @@ -423,15 +435,13 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) end # infix (i.e. "x<:y" or "x = y") - elseif (head in expr_infix && nargs==2) || (is(head,:(:)) && nargs==3) - show_list(io, args, head, indent, 0, true) - - elseif head in expr_infix_wide && nargs == 2 + elseif (head in expr_infix_any && nargs==2) || (is(head,:(:)) && nargs==3) func_prec = operator_precedence(head) + head_ = head in expr_infix_wide ? " $head " : head if func_prec < prec - show_enclosed_list(io, '(', args, " $head ", ')', indent, func_prec, true) + show_enclosed_list(io, '(', args, head_, ')', indent, func_prec, true) else - show_list(io, args, " $head ", indent, func_prec, true) + show_list(io, args, head_, indent, func_prec, true) end # list (i.e. "(1,2,3)" or "[1,2,3]") @@ -460,6 +470,10 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) func_prec = operator_precedence(func) func_args = args[2:end] + if in(ex.args[1], (:box, TopNode(:box), :throw)) || ismodulecall(ex) + show_expr_type_emphasize::Bool = show_type = false + end + # scalar multiplication (i.e. "100x") if (func == :(*) && length(func_args)==2 && isa(func_args[1], Real) && isa(func_args[2], Symbol)) @@ -579,6 +593,7 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) show_list(io, args, ' ', indent) elseif is(head, :line) && 1 <= nargs <= 2 + show_type = false show_linenumber(io, args...) elseif is(head, :if) && nargs == 3 # if/else @@ -660,6 +675,8 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) # print anything else as "Expr(head, args...)" else + show_type = false + show_expr_type_emphasize::Bool = in(ex.head, (:lambda, :method)) print(io, "\$(Expr(") show(io, ex.head) for arg in args @@ -669,7 +686,31 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) print(io, "))") end - show_expr_type(io, ex.typ) + if ex.head == :(=) + show_type = show_type_assignment(ex.args[2]) + elseif in(ex.head, (:boundscheck, :gotoifnot, :return)) + show_type = false + end + + if show_type + show_expr_type(io, ex.typ) + end + + show_expr_type_emphasize::Bool = state +end + +show_type_assignment(::Number) = false +show_type_assignment(::(Number...)) = false +show_type_assignment(::Expr) = false +show_type_assignment(::SymbolNode) = false +show_type_assignment(::LambdaStaticData) = false +show_type_assignment(a) = true + +function ismodulecall(ex::Expr) + ex.head == :call && ex.args[1] == TopNode(:getfield) && + isa(ex.args[2], Symbol) && + isdefined(current_module(), ex.args[2]) && + isa(getfield(current_module(), ex.args[2]), Module) end # dump & xdump - structured tree representation like R's str() diff --git a/base/sparse/csparse.jl b/base/sparse/csparse.jl index 4794e3c511b13..c77f0bc0d5b31 100644 --- a/base/sparse/csparse.jl +++ b/base/sparse/csparse.jl @@ -47,6 +47,7 @@ function sparse{Tv,Ti<:Integer}(I::AbstractVector{Ti}, J::AbstractVector{Ti}, iind = I[k] jind = J[k] ((iind > 0) && (jind > 0)) || throw(BoundsError()) + ((iind <= nrow) && (jind <= ncol)) || throw(BoundsError()) p = Wj[iind] Vk = V[k] if Vk != 0 diff --git a/base/subarray.jl b/base/subarray.jl index 9d32f277ba93a..5fe308c550fac 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -32,7 +32,10 @@ parent(a::AbstractArray) = a parentindexes(a::AbstractArray) = ntuple(ndims(a), i->1:size(a,i)) ## SubArray creation -stagedfunction slice{T,NP}(A::AbstractArray{T,NP}, I::ViewIndex...) +# Drops singleton dimensions (those indexed with a scalar) +slice(A::AbstractArray, I::ViewIndex...) = _slice(A, I) +slice(A::AbstractArray, I::(ViewIndex...)) = _slice(A, I) +stagedfunction _slice{T,NP,IndTypes}(A::AbstractArray{T,NP}, I::IndTypes) N = 0 sizeexprs = Array(Any, 0) for k = 1:length(I) @@ -52,8 +55,11 @@ stagedfunction slice{T,NP}(A::AbstractArray{T,NP}, I::ViewIndex...) end end -# Conventional style (drop trailing singleton dimensions, keep any other singletons) -stagedfunction sub{T,NP}(A::AbstractArray{T,NP}, I::ViewIndex...) +# Conventional style (drop trailing singleton dimensions, keep any +# other singletons) +sub(A::AbstractArray, I::ViewIndex...) = _sub(A, I) +sub(A::AbstractArray, I::(ViewIndex...)) = _sub(A, I) +stagedfunction _sub{T,NP,IndTypes}(A::AbstractArray{T,NP}, I::IndTypes) sizeexprs = Array(Any, 0) Itypes = Array(Any, 0) Iexprs = Array(Any, 0) @@ -87,7 +93,7 @@ end # Constructing from another SubArray # This "pops" the old SubArray and creates a more compact one -stagedfunction slice{T,NV,PV,IV,PLD}(V::SubArray{T,NV,PV,IV,PLD}, I::ViewIndex...) +stagedfunction _slice{T,NV,PV,IV,PLD,IndTypes}(V::SubArray{T,NV,PV,IV,PLD}, I::IndTypes) N = 0 sizeexprs = Array(Any, 0) indexexprs = Array(Any, 0) @@ -157,7 +163,7 @@ stagedfunction slice{T,NV,PV,IV,PLD}(V::SubArray{T,NV,PV,IV,PLD}, I::ViewIndex.. end end -stagedfunction sub{T,NV,PV,IV,PLD}(V::SubArray{T,NV,PV,IV,PLD}, I::ViewIndex...) +stagedfunction _sub{T,NV,PV,IV,PLD,IndTypes}(V::SubArray{T,NV,PV,IV,PLD}, I::IndTypes) N = length(I) while N > 0 && I[N] <: Real N -= 1 diff --git a/base/test.jl b/base/test.jl index 0e1b76bd082a2..7f0136bdf15a3 100644 --- a/base/test.jl +++ b/base/test.jl @@ -54,7 +54,7 @@ end function do_test_throws(body, qex, bt, extype) handler()(try body() - Failure(qex) + Failure(qex, "$qex did not throw $(extype == nothing ? "anything" : extype)") catch err if extype == nothing Base.warn(""" @@ -66,7 +66,7 @@ function do_test_throws(body, qex, bt, extype) if isa(err, extype) Success(qex) else - Failure(qex) + Failure(qex, "$err was thrown instead of $extype") end end end) diff --git a/base/util.jl b/base/util.jl index 62c10d4a6648a..af7ac1495332e 100644 --- a/base/util.jl +++ b/base/util.jl @@ -242,21 +242,11 @@ end warn(err::Exception; prefix="ERROR: ", kw...) = warn(sprint(io->showerror(io,err)), prefix=prefix; kw...) -# Julia compiler options struct (see jl_compileropts_t in src/julia.h) -immutable JLCompilerOpts - julia_home::Ptr{Cchar} - julia_bin::Ptr{Cchar} - build_path::Ptr{Cchar} - image_file::Ptr{Cchar} - cpu_target::Ptr{Cchar} - code_coverage::Int8 - malloc_log::Int8 - check_bounds::Int8 - dumpbitcode::Int8 - int_literals::Cint - compile_enabled::Int8 - opt_level::Int8 - depwarn::Int8 +function julia_cmd(julia=joinpath(JULIA_HOME, "julia")) + opts = compileropts() + cpu_target = bytestring(opts.cpu_target) + image_file = bytestring(opts.image_file) + `$julia -C$cpu_target -J$image_file` end -compileropts() = unsafe_load(cglobal(:jl_compileropts, JLCompilerOpts)) +julia_exename() = ccall(:jl_is_debugbuild,Cint,())==0 ? "julia" : "julia-debug" diff --git a/contrib/build_sysimg.jl b/contrib/build_sysimg.jl index a73445a06564a..a4d66d81bb478 100644 --- a/contrib/build_sysimg.jl +++ b/contrib/build_sysimg.jl @@ -1,15 +1,17 @@ #!/usr/bin/env julia -# Build a system image binary at sysimg_path.dlext. By default, put the system image next to libjulia +# Build a system image binary at sysimg_path.dlext. By default, put the system image +# next to libjulia (except on Windows, where it goes in $JULIA_HOME\..\lib\julia) # Allow insertion of a userimg via userimg_path. If sysimg_path.dlext is currently loaded into memory, # don't continue unless force is set to true. Allow targeting of a CPU architecture via cpu_target -const default_sysimg_path = joinpath(dirname(Sys.dlpath("libjulia")),"sys") +@unix_only const default_sysimg_path = joinpath(dirname(Sys.dlpath("libjulia")),"sys") +@windows_only const default_sysimg_path = joinpath(JULIA_HOME,"..","lib","julia","sys") function build_sysimg(sysimg_path=default_sysimg_path, cpu_target="native", userimg_path=nothing; force=false) # Quit out if a sysimg is already loaded and is in the same spot as sysimg_path, unless forcing sysimg = dlopen_e("sys") if sysimg != C_NULL - if !force && Sys.dlpath(sysimg) == "$(sysimg_path).$(Sys.dlext)" - println("System image already loaded at $(Sys.dlpath(sysimg)), set force to override") + if !force && Base.samefile(Sys.dlpath(sysimg), "$(sysimg_path).$(Sys.dlext)") + info("System image already loaded at $(Sys.dlpath(sysimg)), set force to override") return end end @@ -24,14 +26,13 @@ function build_sysimg(sysimg_path=default_sysimg_path, cpu_target="native", user cd(base_dir) do try julia = joinpath(JULIA_HOME, "julia") - julia_libdir = dirname(Sys.dlpath("libjulia")) ld = find_system_linker() # Ensure we have write-permissions to wherever we're trying to write to try - touch("$sysimg_path.$(Sys.dlext)") + touch("$sysimg_path.ji") catch - err_msg = "Unable to modify $sysimg_path.$(Sys.dlext), ensure parent directory exists " + err_msg = "Unable to modify $sysimg_path.ji, ensure parent directory exists " err_msg *= "and is writable. Absolute paths work best. Do you need to run this with sudo?)" error( err_msg ) end @@ -46,50 +47,25 @@ function build_sysimg(sysimg_path=default_sysimg_path, cpu_target="native", user # Start by building sys0.{ji,o} sys0_path = joinpath(dirname(sysimg_path), "sys0") - println("Building sys0.o...") + info("Building sys0.o...") println("$julia -C $cpu_target --build $sys0_path sysimg.jl") run(`$julia -C $cpu_target --build $sys0_path sysimg.jl`) # Bootstrap off of that to create sys.{ji,o} - println("Building sys.o...") + info("Building sys.o...") println("$julia -C $cpu_target --build $sysimg_path -J $sys0_path.ji -f sysimg.jl") run(`$julia -C $cpu_target --build $sysimg_path -J $sys0_path.ji -f sysimg.jl`) - # Link sys.o into sys.$(dlext) - FLAGS = ["-L$julia_libdir"] - if OS_NAME == :Darwin - push!(FLAGS, "-dylib") - push!(FLAGS, "-undefined") - push!(FLAGS, "dynamic_lookup") - push!(FLAGS, "-macosx_version_min") - push!(FLAGS, "10.7") - else - if OS_NAME == :Linux - push!(FLAGS, "-shared") - end - push!(FLAGS, "--unresolved-symbols") - push!(FLAGS, "ignore-all") - end - @windows_only append!(FLAGS, ["-L$JULIA_HOME", "-ljulia", "-lssp"]) - if ld != nothing - println("Linking sys.$(Sys.dlext)") - run(`$ld $FLAGS -o $sysimg_path.$(Sys.dlext) $sysimg_path.o`) - end - - println("System image successfully built at $sysimg_path.$(Sys.dlext)") - @windows_only begin - if convert(VersionNumber, Base.libllvm_version) < v"3.5.0" - LLVM_msg = "Building sys.dll on Windows against LLVM < 3.5.0 can cause incorrect backtraces!" - LLVM_msg *= " Delete generated sys.dll to avoid these problems" - warn( LLVM_msg ) - end + link_sysimg(sysimg_path, ld) + else + info("System image successfully built at $sysimg_path.ji") end - if default_sysimg_path != sysimg_path - println("To run Julia with this image loaded, run: julia -J $sysimg_path.ji") + if !Base.samefile("$default_sysimg_path.ji", "$sysimg_path.ji") + info("To run Julia with this image loaded, run: julia -J $sysimg_path.ji") else - println("Julia will automatically load this system image at next startup") + info("Julia will automatically load this system image at next startup") end finally # Cleanup userimg.jl @@ -109,16 +85,18 @@ function find_system_linker() return ENV["LD"] end - # On Windows, check to see if WinRPM is installed, and if so, see if binutils is installed + # On Windows, check to see if WinRPM is installed, and if so, see if gcc is installed @windows_only try - using WinRPM - if WinRPM.installed("binutils") - ENV["PATH"] = "$(ENV["PATH"]):$(joinpath(WinRPM.installdir,"usr","$(Sys.ARCH)-w64-mingw32","sys-root","mingw","bin"))" + require("WinRPM") + winrpmgcc = joinpath(WinRPM.installdir,"usr","$(Sys.ARCH)-w64-mingw32", + "sys-root","mingw","bin","gcc.exe") + if success(`$winrpmgcc --version`) + return winrpmgcc else throw() end catch - warn("Install Binutils via WinRPM.install(\"binutils\") to generate sys.dll for faster startup times" ) + warn("Install GCC via `Pkg.add(\"WinRPM\"); WinRPM.install(\"gcc\")` to generate sys.dll for faster startup times") end @@ -132,6 +110,39 @@ function find_system_linker() warn( "No supported linker found; startup times will be longer" ) end +# Link sys.o into sys.$(dlext) +function link_sysimg(sysimg_path=default_sysimg_path, ld=find_system_linker()) + julia_libdir = dirname(Sys.dlpath("libjulia")) + + FLAGS = ["-L$julia_libdir"] + if OS_NAME == :Darwin + push!(FLAGS, "-dylib") + push!(FLAGS, "-undefined") + push!(FLAGS, "dynamic_lookup") + push!(FLAGS, "-macosx_version_min") + push!(FLAGS, "10.7") + else + push!(FLAGS, "-shared") + # on windows we link using gcc for now + wl = @windows? "-Wl," : "" + push!(FLAGS, wl * "--unresolved-symbols") + push!(FLAGS, wl * "ignore-all") + end + @windows_only append!(FLAGS, ["-ljulia", "-lssp-0"]) + + info("Linking sys.$(Sys.dlext)") + run(`$ld $FLAGS -o $sysimg_path.$(Sys.dlext) $sysimg_path.o`) + + info("System image successfully built at $sysimg_path.$(Sys.dlext)") + @windows_only begin + if convert(VersionNumber, Base.libllvm_version) < v"3.5.0" + LLVM_msg = "Building sys.dll on Windows against LLVM < 3.5.0 can cause incorrect backtraces!" + LLVM_msg *= " Delete generated sys.dll to avoid these problems" + warn( LLVM_msg ) + end + end +end + # When running this file as a script, try to do so with default values. If arguments are passed # in, use them as the arguments to build_sysimg above if !isinteractive() @@ -144,7 +155,7 @@ if !isinteractive() println(" --help Print out this help text and exit") println() println(" Example:") - println(" build_sysimg.jl /usr/local/lib/julia/sys core2 ~/my_usrimg.jl true") + println(" build_sysimg.jl /usr/local/lib/julia/sys core2 ~/my_usrimg.jl --force") println() println(" Running this script with no arguments is equivalent to calling it via") println(" build_sysimg.jl $(default_sysimg_path) native") diff --git a/contrib/fixup-libgfortran.sh b/contrib/fixup-libgfortran.sh index 4d6fde7915d39..dd8a99d63ce96 100755 --- a/contrib/fixup-libgfortran.sh +++ b/contrib/fixup-libgfortran.sh @@ -39,12 +39,12 @@ find_shlib () for lib in arpack openlibm openspecfun lapack; do if [ -f "$private_libdir/lib$lib.$SHLIB_EXT" ]; then LIBGFORTRAN_DIRS="$LIBGFORTRAN_DIRS $(dirname $(find_shlib $lib libgfortran) 2>/dev/null)" - LIBGFORTRAN_DIRS="$LIBGFORTRAN_DIRS $(dirname $(find_shlib $lib libgcc) 2>/dev/null)" + LIBGFORTRAN_DIRS="$LIBGFORTRAN_DIRS $(dirname $(find_shlib $lib libgcc_s) 2>/dev/null)" + LIBGFORTRAN_DIRS="$LIBGFORTRAN_DIRS $(dirname $(find_shlib $lib libquadmath) 2>/dev/null)" fi done LIBGFORTRAN_DIRS=$(echo "$LIBGFORTRAN_DIRS" | tr " " "\n" | sort | uniq | grep -v '^$' | tr "\n" " ") -echo "Found traces of libgfortran/libgcc in $LIBGFORTRAN_DIRS" # If only we could agree on something if [ "$UNAME" = "Linux" ]; then @@ -65,6 +65,18 @@ for namext in $NAMEXTS; do done done +# Add possible internal directories to LIBGFORTRAN_DIRS +for lib in gfortran.3 quadmath.0 gcc_s.1 ; do + if [ -f "$private_libdir/lib$lib.$SHLIB_EXT" ]; then + LIBGFORTRAN_DIRS="$LIBGFORTRAN_DIRS $(dirname $(find_shlib $lib libgfortran) 2>/dev/null)" + LIBGFORTRAN_DIRS="$LIBGFORTRAN_DIRS $(dirname $(find_shlib $lib libgcc_s) 2>/dev/null)" + LIBGFORTRAN_DIRS="$LIBGFORTRAN_DIRS $(dirname $(find_shlib $lib libquadmath) 2>/dev/null)" + fi +done + +LIBGFORTRAN_DIRS=$(echo "$LIBGFORTRAN_DIRS" | tr " " "\n" | sort | uniq | grep -v '^$' | tr "\n" " ") +echo "Found traces of libgfortran/libgcc in $LIBGFORTRAN_DIRS" + # Do the private_libdir libraries... if [ "$UNAME" = "Darwin" ]; then diff --git a/contrib/julia-mode.el b/contrib/julia-mode.el index c18fd2ca641c1..d3d5a2a3882af 100644 --- a/contrib/julia-mode.el +++ b/contrib/julia-mode.el @@ -159,7 +159,8 @@ This function provides equivalent functionality, but makes no efforts to optimis (not (any "(" ")")))) ")" (* space) - "=")) + "=" + (not (any "=")))) (defconst julia-type-regex (rx symbol-start (or "immutable" "type" "abstract") (1+ space) (group (1+ (or word (syntax symbol)))))) diff --git a/deps/Makefile b/deps/Makefile index 72966b3a4afc5..e462deeba3688 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -1813,7 +1813,7 @@ distclean-libgit2: -rm -rf libgit2-$(LIBGIT2_VER).tar.gz libgit2-$(LIBGIT2_VER).zip libgit2-$(LIBGIT2_VER) get-libgit2: libgit2-$(LIBGIT2_VER).tar.gz -configure-libgit2: libgit2-$(LIBGIT2_VER)/Makefile +configure-libgit2: libgit2-$(LIBGIT2_VER)/build/Makefile compile-libgit2: $(LIBGIT2_OBJ_SOURCE) check-libgit2: libgit2-$(LIBGIT2_VER)/build/checked install-libgit2: $(LIBGIT2_OBJ_TARGET) diff --git a/doc/devdocs/C.rst b/doc/devdocs/C.rst index ae47834c6f4fb..8597a5f32448b 100644 --- a/doc/devdocs/C.rst +++ b/doc/devdocs/C.rst @@ -1,6 +1,6 @@ :orphan: -.. _devdocs-index: +.. _devdocs-c-index: ##################################### Developing/debugging Julia's C code diff --git a/doc/devdocs/sysimg.rst b/doc/devdocs/sysimg.rst index 15654c8125205..6d2f1f0062b1c 100644 --- a/doc/devdocs/sysimg.rst +++ b/doc/devdocs/sysimg.rst @@ -24,7 +24,7 @@ This will include a ``build_sysimg()`` function: .. function:: build_sysimg(sysimg_path=default_sysimg_path, cpu_target="native", userimg_path=nothing; force=false) - Rebuild the system image. Store it in ``sysimg_path``, which defaults to a file named ``sys.ji`` that sits in the same folder as ``libjulia.{so,dll,dylib}``. + Rebuild the system image. Store it in ``sysimg_path``, which defaults to a file named ``sys.ji`` that sits in the same folder as ``libjulia.{so,dylib}``, except on Windows where it defaults to ``JULIA_HOME/../lib/julia/sys.ji``. Use the cpu instruction set given by ``cpu_target``. Valid CPU targets are the same as for the ``-C`` option to ``julia``, or the ``-march`` option to ``gcc``. Defaults to ``native``, which means to use all CPU instructions available on the current processor. Include the user image file given by ``userimg_path``, which should contain directives such as ``using MyPackage`` to include that package in the new system image. New system image will not replace an older image unless ``force`` is set to true. diff --git a/doc/manual/arrays.rst b/doc/manual/arrays.rst index e318e86e1db5c..d27751b3dc341 100644 --- a/doc/manual/arrays.rst +++ b/doc/manual/arrays.rst @@ -84,7 +84,7 @@ Function Description :func:`reinterpret(type, A) ` an array with the same binary data as the given array, but with the specified element type :func:`rand(dims) ` ``Array`` of ``Float64``\ s with random, iid[#]_ and uniformly - distributed values in [0,1) + distributed values in the half-open interval [0, 1) :func:`randn(dims) ` ``Array`` of ``Float64``\ s with random, iid and standard normally distributed random values :func:`eye(n) ` ``n``-by-``n`` identity matrix @@ -692,7 +692,7 @@ reference. | :func:`sprand(m,n,d) ` | :func:`rand(m,n) ` | Creates a *m*-by-*n* random matrix (of | | | | density *d*) with iid non-zero elements | | | | distributed uniformly on the | -| | | interval [0, 1]. | +| | | half-open interval [0, 1). | +----------------------------------------+----------------------------------+--------------------------------------------+ | :func:`sprandn(m,n,d) ` | :func:`randn(m,n) ` | Creates a *m*-by-*n* random matrix (of | | | | density *d*) with iid non-zero elements | diff --git a/doc/manual/complex-and-rational-numbers.rst b/doc/manual/complex-and-rational-numbers.rst index 370852b380861..597916498ead4 100644 --- a/doc/manual/complex-and-rational-numbers.rst +++ b/doc/manual/complex-and-rational-numbers.rst @@ -1,5 +1,7 @@ .. _man-complex-and-rational-numbers: +.. currentmodule:: Base + ****************************** Complex and Rational Numbers ****************************** @@ -16,7 +18,7 @@ expected. Complex Numbers --------------- -The global constant ``im`` is bound to the complex number *i*, +The global constant :const:`im` is bound to the complex number *i*, representing the principal square root of -1. It was deemed harmful to co-opt the name ``i`` for a global constant, since it is such a popular index variable name. Since Julia allows numeric literals to be @@ -122,10 +124,10 @@ Standard functions to manipulate complex values are provided: julia> angle(1 + 2im) 1.1071487177940904 -As usual, the absolute value (``abs``) of a complex number is its -distance from zero. The ``abs2`` function gives the square of the +As usual, the absolute value (:func:`abs`) of a complex number is its +distance from zero. :func:`abs2` gives the square of the absolute value, and is of particular use for complex numbers where it -avoids taking a square root. The ``angle`` function returns the phase +avoids taking a square root. :func:`angle` returns the phase angle in radians (also known as the *argument* or *arg* function). The full gamut of other :ref:`man-elementary-functions` is also defined for complex numbers: @@ -149,7 +151,7 @@ for complex numbers: Note that mathematical functions typically return real values when applied to real numbers and complex values when applied to complex numbers. -For example, ``sqrt`` behaves differently when applied to ``-1`` +For example, :func:`sqrt` behaves differently when applied to ``-1`` versus ``-1 + 0im`` even though ``-1 == -1 + 0im``: .. doctest:: @@ -172,7 +174,7 @@ multiplication must be explicitly written out: julia> a = 1; b = 2; a + b*im 1 + 2im -However, this is *not* recommended; Use the ``complex`` function instead to +However, this is *not* recommended; Use the :func:`complex` function instead to construct a complex value directly from its real and imaginary parts.: .. doctest:: @@ -182,7 +184,7 @@ construct a complex value directly from its real and imaginary parts.: This construction avoids the multiplication and addition operations. -``Inf`` and ``NaN`` propagate through complex numbers in the real +:const:`Inf` and :const:`NaN` propagate through complex numbers in the real and imaginary parts of a complex number as described in the :ref:`man-special-floats` section: @@ -200,7 +202,7 @@ Rational Numbers ---------------- Julia has a rational number type to represent exact ratios of integers. -Rationals are constructed using the ``//`` operator: +Rationals are constructed using the :obj:`//` operator: .. doctest:: @@ -227,7 +229,7 @@ are reduced to lowest terms such that the denominator is non-negative: This normalized form for a ratio of integers is unique, so equality of rational values can be tested by checking for equality of the numerator and denominator. The standardized numerator and denominator of a -rational value can be extracted using the ``num`` and ``den`` functions: +rational value can be extracted using the :func:`num` and :func:`den` functions: .. doctest:: @@ -296,7 +298,7 @@ Constructing infinite rational values is acceptable: julia> typeof(ans) Rational{Int64} (constructor with 1 method) -Trying to construct a ``NaN`` rational value, however, is not: +Trying to construct a :const:`NaN` rational value, however, is not: .. doctest:: diff --git a/doc/manual/constructors.rst b/doc/manual/constructors.rst index b73918343ce9b..2894212d72bd3 100644 --- a/doc/manual/constructors.rst +++ b/doc/manual/constructors.rst @@ -1,5 +1,7 @@ .. _man-constructors: +.. currentmodule:: Base + ************** Constructors ************** @@ -396,10 +398,10 @@ outer constructor method: julia> Point(x::Int64, y::Float64) = Point(convert(Float64,x),y); -This method uses the ``convert`` function to explicitly convert ``x`` to -``Float64`` and then delegates construction to the general constructor -for the case where both arguments are ``Float64``. With this method -definition what was previously a "no method" error now successfully +This method uses the :func:`convert` function to explicitly convert ``x`` to +:class:`Float64` and then delegates construction to the general constructor +for the case where both arguments are :class:`Float64`. With this method +definition what was previously a :exc:`MethodError` now successfully creates a point of type ``Point{Float64}``: .. doctest:: @@ -428,9 +430,9 @@ the following outer method definition to make all calls to the general julia> Point(x::Real, y::Real) = Point(promote(x,y)...); The ``promote`` function converts all its arguments to a common type -— in this case ``Float64``. With this method definition, the ``Point`` +— in this case :class:`Float64`. With this method definition, the ``Point`` constructor promotes its arguments the same way that numeric operators -like ``+`` do, and works for all kinds of real numbers: +like :obj:`+` do, and works for all kinds of real numbers: .. doctest:: @@ -489,13 +491,13 @@ which implements Julia's :ref:`man-rational-numbers`:: end The first line — ``immutable Rational{T<:Int} <: Real`` — declares that -``Rational`` takes one type parameter of an integer type, and is itself +:class:`Rational` takes one type parameter of an integer type, and is itself a real type. The field declarations ``num::T`` and ``den::T`` indicate that the data held in a ``Rational{T}`` object are a pair of integers of type ``T``, one representing the rational value's numerator and the other representing its denominator. -Now things get interesting. ``Rational`` has a single inner constructor +Now things get interesting. :class:`Rational` has a single inner constructor method which checks that both of ``num`` and ``den`` aren't zero and ensures that every rational is constructed in "lowest terms" with a non-negative denominator. This is accomplished by dividing the given @@ -504,10 +506,10 @@ computed using the ``gcd`` function. Since ``gcd`` returns the greatest common divisor of its arguments with sign matching the first argument (``den`` here), after this division the new value of ``den`` is guaranteed to be non-negative. Because this is the only inner -constructor for ``Rational``, we can be certain that ``Rational`` +constructor for :class:`Rational`, we can be certain that :class:`Rational` objects are always constructed in this normalized form. -``Rational`` also provides several outer constructor methods for +:class:`Rational` also provides several outer constructor methods for convenience. The first is the "standard" general constructor that infers the type parameter ``T`` from the type of the numerator and denominator when they have the same type. The second applies when the given @@ -518,17 +520,17 @@ turns integer values into rationals by supplying a value of ``1`` as the denominator. Following the outer constructor definitions, we have a number of methods -for the ``//`` operator, which provides a syntax for writing rationals. -Before these definitions, ``//`` is a completely undefined operator with +for the :obj:`//` operator, which provides a syntax for writing rationals. +Before these definitions, :obj:`//` is a completely undefined operator with only syntax and no meaning. Afterwards, it behaves just as described in :ref:`man-rational-numbers` — its entire behavior is defined in these few lines. The first and most -basic definition just makes ``a//b`` construct a ``Rational`` by -applying the ``Rational`` constructor to ``a`` and ``b`` when they are -integers. When one of the operands of ``//`` is already a rational +basic definition just makes ``a//b`` construct a :class:`Rational` by +applying the :class:`Rational` constructor to ``a`` and ``b`` when they are +integers. When one of the operands of :obj:`//` is already a rational number, we construct a new rational for the resulting ratio slightly differently; this behavior is actually identical to division of a -rational with an integer. Finally, applying ``//`` to complex integral +rational with an integer. Finally, applying :obj:`//` to complex integral values creates an instance of ``Complex{Rational}`` — a complex number whose real and imaginary parts are rationals: @@ -543,8 +545,8 @@ whose real and imaginary parts are rationals: julia> ans <: Complex{Rational} false -Thus, although the ``//`` operator usually returns an instance of -``Rational``, if either of its arguments are complex integers, it will +Thus, although the :obj:`//` operator usually returns an instance of +:class:`Rational`, if either of its arguments are complex integers, it will return an instance of ``Complex{Rational}`` instead. The interested reader should consider perusing the rest of `rational.jl `_: diff --git a/doc/manual/control-flow.rst b/doc/manual/control-flow.rst index 593b29608d078..c037820d0d189 100644 --- a/doc/manual/control-flow.rst +++ b/doc/manual/control-flow.rst @@ -1,5 +1,7 @@ .. _man-control-flow: +.. currentmodule:: Base + ************** Control Flow ************** @@ -13,11 +15,11 @@ Julia provides a variety of control flow constructs: ``&&``, ``||`` and chained comparisons. - :ref:`man-loops`: ``while`` and ``for``. - :ref:`man-exception-handling`: - ``try``-``catch``, ``error`` and ``throw``. -- :ref:`man-tasks`: ``yieldto``. + ``try``-``catch``, :func:`error` and :func:`throw`. +- :ref:`man-tasks`: :func:`yieldto`. The first five control flow mechanisms are standard to high-level -programming languages. Tasks are not so standard: they provide non-local +programming languages. :class:`Task`\ s are not so standard: they provide non-local control flow, making it possible to switch between temporarily-suspended computations. This is a powerful construct: both exception handling and cooperative multitasking are implemented in Julia using tasks. Everyday @@ -119,6 +121,39 @@ blocks as desired can be used. The condition expressions in the evaluates to ``true``, after which the associated block is evaluated, and no further condition expressions or blocks are evaluated. +``if`` blocks are "leaky", i.e. they do not introduce a local scope. +This means that new variables defined inside the ``ìf`` clauses can +be used after the ``if`` block, even if they weren't defined before. +So, we could have defined the ``test`` function above as + +.. doctest:: + + julia> function test(x,y) + if x < y + relation = "less than" + elseif x == y + relation = "equal to" + else + relation = "greater than" + end + println("x is ", relation, " than y.") + end + +``if`` blocks also return a value, which may seem unintuitive to users +coming from many other languages. This value is simply the return value +of the last executed statement in the branch that was chosen, so + +.. doctest:: + + julia> x = 3 + + julia> if x > 0 + "positive!" + else + "negative..." + end + "positive!" + Note that very short conditional statements (one-liners) are frequently expressed using Short-Circuit Evaluation in Julia, as outlined in the next section. @@ -533,53 +568,54 @@ diagnostic error message, or if the programmer has provided code to handle such exceptional circumstances, allow that code to take the appropriate action. -Built-in ``Exception``\ s -~~~~~~~~~~~~~~~~~~~~~~~~~ - -``Exception``\ s are thrown when an unexpected condition has occurred. The -built-in ``Exception``\ s listed below all interrupt the normal flow of control. - -+------------------------+ -| ``Exception`` | -+========================+ -| ``ArgumentError`` | -+------------------------+ -| ``BoundsError`` | -+------------------------+ -| ``DivideError`` | -+------------------------+ -| ``DomainError`` | -+------------------------+ -| ``EOFError`` | -+------------------------+ -| ``ErrorException`` | -+------------------------+ -| ``InexactError`` | -+------------------------+ -| ``InterruptException`` | -+------------------------+ -| ``KeyError`` | -+------------------------+ -| ``LoadError`` | -+------------------------+ -| ``MemoryError`` | -+------------------------+ -| ``MethodError`` | -+------------------------+ -| ``OverflowError`` | -+------------------------+ -| ``ParseError`` | -+------------------------+ -| ``SystemError`` | -+------------------------+ -| ``TypeError`` | -+------------------------+ -| ``UndefRefError`` | -+------------------------+ -| ``UndefVarError`` | -+------------------------+ - -For example, the ``sqrt`` function throws a ``DomainError()`` if applied to a +Built-in :exc:`Exception`\ s +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:exc:`Exception`\ s are thrown when an unexpected condition has occurred. The +built-in :exc:`Exception`\ s listed below all interrupt the normal flow of control. + ++---------------------------+ +| :exc:`Exception` | ++===========================+ +| :exc:`ArgumentError` | ++---------------------------+ +| :exc:`BoundsError` | ++---------------------------+ +| :exc:`DivideError` | ++---------------------------+ +| :exc:`DomainError` | ++---------------------------+ +| :exc:`EOFError` | ++---------------------------+ +| :exc:`ErrorException` | ++---------------------------+ +| :exc:`InexactError` | ++---------------------------+ +| :exc:`InterruptException` | ++---------------------------+ +| :exc:`KeyError` | ++---------------------------+ +| :exc:`LoadError` | ++---------------------------+ +| :exc:`MemoryError` | ++---------------------------+ +| :exc:`MethodError` | ++---------------------------+ +| :exc:`OverflowError` | ++---------------------------+ +| :exc:`ParseError` | ++---------------------------+ +| :exc:`SystemError` | ++---------------------------+ +| :exc:`TypeError` | ++---------------------------+ +| :exc:`UndefRefError` | ++---------------------------+ +| :exc:`UndefVarError` | ++---------------------------+ + + +For example, the :func:`sqrt` function throws a :exc:`DomainError` if applied to a negative real value: .. doctest:: @@ -596,11 +632,11 @@ You may define your own exceptions in the following way: julia> type MyCustomException <: Exception end -The ``throw`` function -~~~~~~~~~~~~~~~~~~~~~~ +The :func:`throw` function +~~~~~~~~~~~~~~~~~~~~~~~~~~ -Exceptions can be created explicitly with ``throw``. For example, a function -defined only for nonnegative numbers could be written to ``throw`` a ``DomainError`` +Exceptions can be created explicitly with :func:`throw`. For example, a function +defined only for nonnegative numbers could be written to :func:`throw` a :exc:`DomainError` if the argument is negative: .. doctest:: @@ -615,8 +651,8 @@ if the argument is negative: ERROR: DomainError in f at none:1 -Note that ``DomainError`` without parentheses is not an exception, but a type of -exception. It needs to be called to obtain an ``Exception`` object: +Note that :exc:`DomainError` without parentheses is not an exception, but a type of +exception. It needs to be called to obtain an :exc:`Exception` object: .. doctest:: @@ -635,7 +671,7 @@ error reporting: ERROR: x not defined This mechanism can be implemented easily by custom exception types following -the way ``UndefVarError`` is written: +the way :exc:`UndefVarError` is written: .. doctest:: @@ -647,12 +683,12 @@ the way ``UndefVarError`` is written: Errors ~~~~~~ -The ``error`` function is used to produce an ``ErrorException`` that +The :func:`error` function is used to produce an :exc:`ErrorException` that interrupts the normal flow of control. Suppose we want to stop execution immediately if the square root of a negative number is taken. To do this, we can define a fussy version of -the ``sqrt`` function that raises an error if its argument is negative: +the :func:`sqrt` function that raises an error if its argument is negative: .. doctest:: @@ -695,7 +731,7 @@ Warnings and informational messages ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Julia also provides other functions that write messages to the standard error -I/O, but do not throw any ``Exception``\ s and hence do not interrupt +I/O, but do not throw any :exc:`Exception`\ s and hence do not interrupt execution.: .. doctest:: @@ -716,10 +752,10 @@ execution.: The ``try/catch`` statement ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``try/catch`` statement allows for ``Exception``\ s to be tested for. For +The ``try/catch`` statement allows for :exc:`Exception`\ s to be tested for. For example, a customized square root function can be written to automatically call either the real or complex square root method on demand using -``Exception``\ s : +:exc:`Exception`\ s : .. doctest:: @@ -740,7 +776,7 @@ It is important to note that in real code computing this function, one would compare ``x`` to zero instead of catching an exception. The exception is much slower than simply comparing and branching. -``try/catch`` statements also allow the ``Exception`` to be saved in a +``try/catch`` statements also allow the :exc:`Exception` to be saved in a variable. In this contrived example, the following example calculates the square root of the second element of ``x`` if ``x`` is indexable, otherwise assumes ``x`` is a real number and returns its square root: @@ -791,7 +827,7 @@ The power of the ``try/catch`` construct lies in the ability to unwind a deeply nested computation immediately to a much higher level in the stack of calling functions. There are situations where no error has occurred, but the ability to unwind the stack and pass a value to a higher level is desirable. Julia -provides the ``rethrow``, ``backtrace`` and ``catch_backtrace`` functions for +provides the :func:`rethrow`, :func:`backtrace` and :func:`catch_backtrace` functions for more advanced error handling. finally Clauses @@ -831,8 +867,8 @@ called by other names, such as symmetric coroutines, lightweight threads, cooperative multitasking, or one-shot continuations. When a piece of computing work (in practice, executing a particular -function) is designated as a ``Task``, it becomes possible to interrupt -it by switching to another ``Task``. The original ``Task`` can later be +function) is designated as a :class:`Task`, it becomes possible to interrupt +it by switching to another :class:`Task`. The original :class:`Task` can later be resumed, at which point it will pick up right where it left off. At first, this may seem similar to a function call. However there are two key differences. First, switching tasks does not use any space, so any @@ -852,8 +888,8 @@ producer may have more values to generate and so might not yet be ready to return. With tasks, the producer and consumer can both run as long as they need to, passing values back and forth as necessary. -Julia provides the functions ``produce`` and ``consume`` for solving -this problem. A producer is a function that calls ``produce`` on each +Julia provides the functions :func:`produce` and :func:`consume` for solving +this problem. A producer is a function that calls :func:`produce` on each value it needs to produce: .. doctest:: @@ -866,8 +902,8 @@ value it needs to produce: produce("stop") end; -To consume values, first the producer is wrapped in a ``Task``, -then ``consume`` is called repeatedly on that object: +To consume values, first the producer is wrapped in a :class:`Task`, +then :func:`consume` is called repeatedly on that object: .. doctest:: @@ -892,7 +928,7 @@ then ``consume`` is called repeatedly on that object: "stop" One way to think of this behavior is that ``producer`` was able to -return multiple times. Between calls to ``produce``, the producer's +return multiple times. Between calls to :func:`produce`, the producer's execution is suspended and the consumer has control. A Task can be used as an iterable object in a ``for`` loop, in which @@ -910,7 +946,7 @@ case the loop variable takes on all the produced values: 8 stop -Note that the ``Task()`` constructor expects a 0-argument function. A +Note that the :func:`Task` constructor expects a 0-argument function. A common pattern is for the producer to be parameterized, in which case a partial function application is needed to create a 0-argument :ref:`anonymous function `. This can be done either @@ -924,35 +960,36 @@ directly or by use of a convenience macro:: # or, equivalently taskHdl = @task mytask(7) -``produce`` and ``consume`` do not launch threads that can run on separate CPUs. +:func:`produce` and :func:`consume` do not launch threads that can run on separate CPUs. True kernel threads are discussed under the topic of :ref:`man-parallel-computing`. Core task operations ~~~~~~~~~~~~~~~~~~~~ -While ``produce`` and ``consume`` illustrate the essential nature of tasks, they +While :func:`produce` and :func:`consume` illustrate the essential nature of tasks, they are actually implemented as library functions using a more primitive function, -``yieldto``. ``yieldto(task,value)`` suspends the current task, switches -to the specified ``task``, and causes that task's last ``yieldto`` call to return -the specified ``value``. Notice that ``yieldto`` is the only operation required +:func:`yieldto`. ``yieldto(task,value)`` suspends the current task, switches +to the specified ``task``, and causes that task's last :func:`yieldto` call to return +the specified ``value``. Notice that :func:`yieldto` is the only operation required to use task-style control flow; instead of calling and returning we are always just switching to a different task. This is why this feature is also called "symmetric coroutines"; each task is switched to and from using the same mechanism. -``yieldto`` is powerful, but most uses of tasks do not invoke it directly. +:func:`yieldto` is powerful, but most uses of tasks do not invoke it directly. Consider why this might be. If you switch away from the current task, you will probably want to switch back to it at some point, but knowing when to switch back, and knowing which task has the responsibility of switching back, can -require considerable coordination. For example, ``produce`` needs to maintain +require considerable coordination. For example, :func:`produce` needs to maintain some state to remember who the consumer is. Not needing to manually keep track -of the consuming task is what makes ``produce`` easier to use than ``yieldto``. +of the consuming task is what makes :func:`produce` easier to use than :func:`yieldto`. -In addition to ``yieldto``, a few other basic functions are needed to use tasks +In addition to :func:`yieldto`, a few other basic functions are needed to use tasks effectively. -``current_task()`` gets a reference to the currently-running task. -``istaskdone(t)`` queries whether a task has exited. -``istaskstarted(t)`` queries whether a task has run yet. -``task_local_storage`` manipulates a key-value store specific to the current task. + +- :func:`current_task` gets a reference to the currently-running task. +- :func:`istaskdone` queries whether a task has exited. +- :func:`istaskstarted` queries whether a task has run yet. +- :func:`task_local_storage` manipulates a key-value store specific to the current task. Tasks and events ~~~~~~~~~~~~~~~~ @@ -962,27 +999,27 @@ requests, and are performed by a scheduler included in the standard library. The scheduler maintains a queue of runnable tasks, and executes an event loop that restarts tasks based on external events such as message arrival. -The basic function for waiting for an event is ``wait``. Several objects -implement ``wait``; for example, given a ``Process`` object, ``wait`` will -wait for it to exit. ``wait`` is often implicit; for example, a ``wait`` -can happen inside a call to ``read`` to wait for data to be available. +The basic function for waiting for an event is :func:`wait`. Several objects +implement :func:`wait`; for example, given a :class:`Process` object, :func:`wait` will +wait for it to exit. :func:`wait` is often implicit; for example, a :func:`wait` +can happen inside a call to :func:`read` to wait for data to be available. -In all of these cases, ``wait`` ultimately operates on a ``Condition`` +In all of these cases, :func:`wait` ultimately operates on a :class:`Condition` object, which is in charge of queueing and restarting tasks. When a task -calls ``wait`` on a ``Condition``, the task is marked as non-runnable, added +calls :func:`wait` on a :class:`Condition`, the task is marked as non-runnable, added to the condition's queue, and switches to the scheduler. The scheduler will then pick another task to run, or block waiting for external events. -If all goes well, eventually an event handler will call ``notify`` on the +If all goes well, eventually an event handler will call :func:`notify` on the condition, which causes tasks waiting for that condition to become runnable again. -A task created explicitly by calling ``Task`` is initially not known to the -scheduler. This allows you to manage tasks manually using ``yieldto`` if +A task created explicitly by calling :class:`Task` is initially not known to the +scheduler. This allows you to manage tasks manually using :func:`yieldto` if you wish. However, when such a task waits for an event, it still gets restarted automatically when the event happens, as you would expect. It is also possible to make the scheduler run a task whenever it can, without necessarily -waiting for any events. This is done by calling ``schedule(task)``, or using -the ``@schedule`` or ``@async`` macros (see :ref:`man-parallel-computing` for +waiting for any events. This is done by calling :func:`schedule`, or using +the :obj:`@schedule` or :obj:`@async` macros (see :ref:`man-parallel-computing` for more details). Task states diff --git a/doc/manual/dates.rst b/doc/manual/dates.rst index 451d2ce76bece..a356df0c18b53 100644 --- a/doc/manual/dates.rst +++ b/doc/manual/dates.rst @@ -1,18 +1,20 @@ .. _man-dates: +.. currentmodule:: Base.Dates + ************************************* Date and DateTime ************************************* -The ``Dates`` module provides two types for working with dates: ``Date`` and ``DateTime``, representing day and millisecond precision, respectively; both are subtypes of the abstract ``TimeType``. The motivation for distinct types is simple: some operations are much simpler, both in terms of code and mental reasoning, when the complexities of greater precision don't have to be dealt with. For example, since the ``Date`` type only resolves to the precision of a single date (i.e. no hours, minutes, or seconds), normal considerations for time zones, daylight savings/summer time, and leap seconds are unnecessary and avoided. +The :mod:`Dates` module provides two types for working with dates: :class:`Date` and :class:`DateTime`, representing day and millisecond precision, respectively; both are subtypes of the abstract :class:`TimeType`. The motivation for distinct types is simple: some operations are much simpler, both in terms of code and mental reasoning, when the complexities of greater precision don't have to be dealt with. For example, since the :class:`Date` type only resolves to the precision of a single date (i.e. no hours, minutes, or seconds), normal considerations for time zones, daylight savings/summer time, and leap seconds are unnecessary and avoided. -Both ``Date`` and ``DateTime`` are basically immutable ``Int64`` wrappers. The single ``instant`` field of either type is actually a ``UTInstant{P}`` type, which represents a continuously increasing machine timeline based on the UT second [1]_. The ``DateTime`` type is *timezone-unaware* (in Python parlance) or is analogous to a *LocalDateTime* in Java 8. Additional time zone functionality can be added through the `Timezones.jl package `_, which compiles the `Olsen Time Zone Database `_. Both ``Date`` and ``DateTime`` are based on the ISO 8601 standard, which follows the proleptic Gregorian calendar. One note is that the ISO 8601 standard is particular about BC/BCE dates. In general, the last day of the BC/BCE era, 1-12-31 BC/BCE, was followed by 1-1-1 AD/CE, thus no year zero exists. The ISO standard, however, states that 1 BC/BCE is year zero, so ``0000-12-31`` is the day before ``0001-01-01``, and year ``-0001`` (yes, negative one for the year) is 2 BC/BCE, year ``-0002`` is 3 BC/BCE, etc. +Both :class:`Date` and :class:`DateTime` are basically immutable ``Int64`` wrappers. The single ``instant`` field of either type is actually a ``UTInstant{P}`` type, which represents a continuously increasing machine timeline based on the UT second [1]_. The :class:`DateTime` type is *timezone-unaware* (in Python parlance) or is analogous to a *LocalDateTime* in Java 8. Additional time zone functionality can be added through the `Timezones.jl package `_, which compiles the `Olsen Time Zone Database `_. Both :class:`Date` and :class:`DateTime` are based on the ISO 8601 standard, which follows the proleptic Gregorian calendar. One note is that the ISO 8601 standard is particular about BC/BCE dates. In general, the last day of the BC/BCE era, 1-12-31 BC/BCE, was followed by 1-1-1 AD/CE, thus no year zero exists. The ISO standard, however, states that 1 BC/BCE is year zero, so ``0000-12-31`` is the day before ``0001-01-01``, and year ``-0001`` (yes, negative one for the year) is 2 BC/BCE, year ``-0002`` is 3 BC/BCE, etc. -.. [1] The notion of the UT second is actually quite fundamental. There are basically two different notions of time generally accepted, one based on the physical rotation of the earth (one full rotation = 1 day), the other based on the SI second (a fixed, constant value). These are radically different! Think about it, a "UT second", as defined relative to the rotation of the earth, may have a different absolute length depending on the day! Anyway, the fact that ``Date`` and ``DateTime`` are based on UT seconds is a simplifying, yet honest assumption so that things like leap seconds and all their complexity can be avoided. This basis of time is formally called `UT `_ or UT1. Basing types on the UT second basically means that every minute has 60 seconds and every day has 24 hours and leads to more natural calculations when working with calendar dates. +.. [1] The notion of the UT second is actually quite fundamental. There are basically two different notions of time generally accepted, one based on the physical rotation of the earth (one full rotation = 1 day), the other based on the SI second (a fixed, constant value). These are radically different! Think about it, a "UT second", as defined relative to the rotation of the earth, may have a different absolute length depending on the day! Anyway, the fact that :class:`Date` and :class:`DateTime` are based on UT seconds is a simplifying, yet honest assumption so that things like leap seconds and all their complexity can be avoided. This basis of time is formally called `UT `_ or UT1. Basing types on the UT second basically means that every minute has 60 seconds and every day has 24 hours and leads to more natural calculations when working with calendar dates. Constructors ------------ -``Date`` and ``DateTime`` types can be constructed by integer or ``Period`` types, by parsing, or through adjusters (more on those later):: +:class:`Date` and :class:`DateTime` types can be constructed by integer or :class:`Period` types, by parsing, or through adjusters (more on those later):: julia> DateTime(2013) 2013-01-01T00:00:00 @@ -50,20 +52,20 @@ Constructors julia> Date(Dates.Month(7),Dates.Year(2013)) 2013-07-01 -``Date`` or ``DateTime`` parsing is accomplished by the use of format strings. Format strings work by the notion of defining *delimited* or *fixed-width* "slots" that contain a period to parse and pass to a ``Date`` or ``DateTime`` constructor. +:class:`Date` or :class:`DateTime` parsing is accomplished by the use of format strings. Format strings work by the notion of defining *delimited* or *fixed-width* "slots" that contain a period to parse and pass to a :class:`Date` or :class:`DateTime` constructor. Delimited slots are marked by specifying the delimiter the parser should expect between two subsequent periods; so ``"y-m-d"`` lets the parser know that between the first and second slots in a date string like ``"2014-07-16"``, it should find the ``-`` character. The ``y``, ``m``, and ``d`` characters let the parser know which periods to parse in each slot. Fixed-width slots are specified by repeating the period character the number of times corresponding to the width. So ``"yyyymmdd"`` would correspond to a date string like ``"20140716"``. The parser distinguishes a fixed-width slot by the absence of a delimiter, noting the transition ``"yyyymm"`` from one period character to the next. -Support for text-form month parsing is also supported through the ``u`` and ``U`` characters, for abbreviated and full-length month names, respectively. By default, only English month names are supported, so ``u`` corresponds to "Jan", "Feb", "Mar", etc. And ``U`` corresponds to "January", "February", "March", etc. Similar to other name=>value mapping functions ``dayname`` and ``monthname``, custom locales can be loaded by passing in the ``locale=>Dict{UTF8String,Int}`` mapping to the ``Dates.MONTHTOVALUEABBR`` and ``Dates.MONTHTOVALUE`` dicts for abbreviated and full-name month names, respectively. +Support for text-form month parsing is also supported through the ``u`` and ``U`` characters, for abbreviated and full-length month names, respectively. By default, only English month names are supported, so ``u`` corresponds to "Jan", "Feb", "Mar", etc. And ``U`` corresponds to "January", "February", "March", etc. Similar to other name=>value mapping functions :func:`dayname` and :func:`monthname`, custom locales can be loaded by passing in the ``locale=>Dict{UTF8String,Int}`` mapping to the :const:`MONTHTOVALUEABBR` and :const:`MONTHTOVALUE` dicts for abbreviated and full-name month names, respectively. A full suite of parsing and formatting tests and examples is available in `tests/dates/io.jl `_. Durations/Comparisons --------------------- -Finding the length of time between two ``Date`` or ``DateTime`` is straightforward given their underlying representation as ``UTInstant{Day}`` and ``UTInstant{Millisecond}``, respectively. The difference between ``Date`` is returned in the number of ``Day``, and ``DateTime`` in the number of ``Millisecond``. Similarly, comparing ``TimeType`` is a simple matter of comparing the underlying machine instants (which in turn compares the internal ``Int64`` values). +Finding the length of time between two :class:`Date` or :class:`DateTime` is straightforward given their underlying representation as ``UTInstant{Day}`` and ``UTInstant{Millisecond}``, respectively. The difference between :class:`Date` is returned in the number of :class:`Day`, and :class:`DateTime` in the number of :class:`Millisecond`. Similarly, comparing :class:`TimeType` is a simple matter of comparing the underlying machine instants (which in turn compares the internal ``Int64`` values). :: @@ -119,7 +121,7 @@ Finding the length of time between two ``Date`` or ``DateTime`` is straightforwa Accessor Functions ------------------ -Because the `Date` and `DateTime` types are stored as single ``Int64`` values, date parts or fields can be retrieved through accessor functions. The lowercase accessors return the field as an integer:: +Because the :class:`Date` and :class:`DateTime` types are stored as single ``Int64`` values, date parts or fields can be retrieved through accessor functions. The lowercase accessors return the field as an integer:: julia> t = Date(2014,1,31) 2014-01-31 @@ -136,7 +138,7 @@ Because the `Date` and `DateTime` types are stored as single ``Int64`` values, d julia> Dates.day(t) 31 -While propercase return the same value in the corresponding ``Period`` type:: +While propercase return the same value in the corresponding :class:`Period` type:: julia> Dates.Year(t) 2014 years @@ -172,7 +174,7 @@ One may also access the underlying ``UTInstant`` or integer value:: Query Functions --------------- -Query functions provide calendrical information about a ``TimeType``. They include information about the day of the week:: +Query functions provide calendrical information about a :class:`TimeType`. They include information about the day of the week:: julia> t = Date(2014,1,31) 2014-01-31 @@ -194,7 +196,7 @@ Month of the year:: julia> Dates.daysinmonth(t) 31 -As well as information about the ``TimeType``'s year and quarter:: +As well as information about the :class:`TimeType`'s year and quarter:: julia> Dates.isleapyear(t) false @@ -208,7 +210,7 @@ As well as information about the ``TimeType``'s year and quarter:: julia> Dates.dayofquarter(t) 31 -The ``dayname`` and ``monthname`` methods can also take an optional ``locale`` keyword that can be used to return the name of the day or month of the year for other languages/locales:: +The :func:`dayname` and :func:`monthname` methods can also take an optional ``locale`` keyword that can be used to return the name of the day or month of the year for other languages/locales:: julia> const french_daysofweek = Dict(1=>"Lundi",2=>"Mardi",3=>"Mercredi",4=>"Jeudi",5=>"Vendredi",6=>"Samedi",7=>"Dimanche"); @@ -218,14 +220,14 @@ The ``dayname`` and ``monthname`` methods can also take an optional ``locale`` k julia> Dates.dayname(t;locale="french") "Vendredi" -Similarly for the ``monthname`` function, a mapping of ``locale=>Dict{Int,UTF8String}`` should be loaded in ``Dates.VALUETOMONTH``. +Similarly for the :func:`monthname` function, a mapping of ``locale=>Dict{Int,UTF8String}`` should be loaded in :const:`VALUETOMONTH`. TimeType-Period Arithmetic -------------------------- It's good practice when using any language/date framework to be familiar with how date-period arithmetic is handled as there are some `tricky issues `_ to deal with (though much less so for day-precision types). -The ``Dates`` module approach tries to follow the simple principle of trying to change as little as possible when doing ``Period`` arithmetic. This approach is also often known as *calendrical* arithmetic or what you would probably guess if someone were to ask you the same calculation in a conversation. Why all the fuss about this? Let's take a classic example: add 1 month to January 31st, 2014. What's the answer? Javascript will say `March 3 `_ (assumes 31 days). PHP says `March 2 `_ (assumes 30 days). The fact is, there is no right answer. In the ``Dates`` module, it gives the result of February 28th. How does it figure that out? I like to think of the classic 7-7-7 gambling game in casinos. +The :mod:`Dates` module approach tries to follow the simple principle of trying to change as little as possible when doing :class:`Period` arithmetic. This approach is also often known as *calendrical* arithmetic or what you would probably guess if someone were to ask you the same calculation in a conversation. Why all the fuss about this? Let's take a classic example: add 1 month to January 31st, 2014. What's the answer? Javascript will say `March 3 `_ (assumes 31 days). PHP says `March 2 `_ (assumes 30 days). The fact is, there is no right answer. In the :mod:`Dates` module, it gives the result of February 28th. How does it figure that out? I like to think of the classic 7-7-7 gambling game in casinos. Now just imagine that instead of 7-7-7, the slots are Year-Month-Day, or in our example, 2014-01-31. When you ask to add 1 month to this date, the month slot is incremented, so now we have 2014-02-31. Then the day number is checked if it is greater than the last valid day of the new month; if it is (as in the case above), the day number is adjusted down to the last valid day (28). What are the ramifications with this approach? Go ahead and add another month to our date, ``2014-02-28 + Month(1) == 2014-03-28``. What? Were you expecting the last day of March? Nope, sorry, remember the 7-7-7 slots. As few slots as possible are going to change, so we first increment the month slot by 1, 2014-03-28, and boom, we're done because that's a valid date. On the other hand, if we were to add 2 months to our original date, 2014-01-31, then we end up with 2014-03-31, as expected. The other ramification of this approach is a loss in associativity when a specific ordering is forced (i.e. adding things in different orders results in different outcomes). For example:: @@ -243,7 +245,7 @@ What's going on there? In the first line, we're adding 1 day to January 29th, wh julia> Date(2014,1,29) + Dates.Month(1) + Dates.Day(1) 2014-03-01 -Tricky? Perhaps. What is an innocent ``Dates`` user to do? The bottom line is to be aware that explicitly forcing a certain associativity, when dealing with months, may lead to some unexpected results, but otherwise, everything should work as expected. Thankfully, that's pretty much the extent of the odd cases in date-period arithmetic when dealing with time in UT (avoiding the "joys" of dealing with daylight savings, leap seconds, etc.). +Tricky? Perhaps. What is an innocent :mod:`Dates` user to do? The bottom line is to be aware that explicitly forcing a certain associativity, when dealing with months, may lead to some unexpected results, but otherwise, everything should work as expected. Thankfully, that's pretty much the extent of the odd cases in date-period arithmetic when dealing with time in UT (avoiding the "joys" of dealing with daylight savings, leap seconds, etc.). Adjuster Functions @@ -251,7 +253,7 @@ Adjuster Functions As convenient as date-period arithmetics are, often the kinds of calculations needed on dates take on a *calendrical* or *temporal* nature rather than a fixed number of periods. Holidays are a perfect example; most follow rules such as "Memorial Day = Last Monday of May", or "Thanksgiving = 4th Thursday of November". These kinds of temporal expressions deal with rules relative to the calendar, like first or last of the month, next Tuesday, or the first and third Wednesdays, etc. -The ``Dates`` module provides the *adjuster* API through several convenient methods that aid in simply and succinctly expressing temporal rules. The first group of adjuster methods deal with the first and last of weeks, months, quarters, and years. They each take a single ``TimeType`` as input and return or *adjust to* the first or last of the desired period relative to the input. +The :mod:`Dates` module provides the *adjuster* API through several convenient methods that aid in simply and succinctly expressing temporal rules. The first group of adjuster methods deal with the first and last of weeks, months, quarters, and years. They each take a single :class:`TimeType` as input and return or *adjust to* the first or last of the desired period relative to the input. :: @@ -267,7 +269,7 @@ The ``Dates`` module provides the *adjuster* API through several convenient meth julia> Dates.lastdayofquarter(Date(2014,7,16)) 2014-09-30 -The next two higher-order methods, ``tonext``, and ``toprev``, generalize working with temporal expressions by taking a ``DateFunction`` as first argument, along with a starting ``TimeType``. A ``DateFunction`` is just a function, usually anonymous, that takes a single ``TimeType`` as input and returns a ``Bool``, ``true`` indicating a satisfied adjustment criterion. +The next two higher-order methods, :func:`tonext`, and :func:`toprev`, generalize working with temporal expressions by taking a :class:`DateFunction` as first argument, along with a starting :class:`TimeType`. A :class:`DateFunction` is just a function, usually anonymous, that takes a single :class:`TimeType` as input and returns a ``Bool``, ``true`` indicating a satisfied adjustment criterion. For example:: julia> istuesday = x->Dates.dayofweek(x) == Dates.Tuesday # Returns true if the day of the week of x is Tuesday @@ -290,7 +292,7 @@ This is useful with the do-block syntax for more complex temporal expressions:: end 2014-11-27 -The final method in the adjuster API is the ``recur`` function. ``recur`` vectorizes the adjustment process by taking a start and stop date (optionally specificed by a ``StepRange``), along with a ``DateFunction`` to specify all valid dates/moments to be returned in the specified range. In this case, the ``DateFunction`` is often referred to as the "inclusion" function because it specifies (by returning true) which dates/moments should be included in the returned vector of dates. +The final method in the adjuster API is the :func:`recur` function. :func:`recur` vectorizes the adjustment process by taking a start and stop date (optionally specificed by a :class:`StepRange`), along with a :class:`DateFunction` to specify all valid dates/moments to be returned in the specified range. In this case, the :class:`DateFunction` is often referred to as the "inclusion" function because it specifies (by returning ``true``) which dates/moments should be included in the returned vector of dates. :: @@ -318,7 +320,7 @@ Additional examples and tests are available in `test/dates/adjusters.jl y1 = Dates.Year(1) diff --git a/doc/manual/faq.rst b/doc/manual/faq.rst index d13ce1a88a54f..52e1b7fec9c39 100644 --- a/doc/manual/faq.rst +++ b/doc/manual/faq.rst @@ -1,5 +1,7 @@ .. _man-faq: +.. currentmodule:: Base + **************************** Frequently Asked Questions **************************** @@ -18,7 +20,7 @@ If memory usage is your concern, you can always replace objects with ones that consume less memory. For example, if ``A`` is a gigabyte-sized array that you no longer need, you can free the memory with ``A = 0``. The memory will be released the next time the garbage -collector runs; you can force this to happen with ``gc()``. +collector runs; you can force this to happen with :func:`gc`. How can I modify the declaration of a type/immutable in my session? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -88,7 +90,7 @@ Here we created a function ``change_array!()``, that assigns ``5`` to the first Can I use ``using`` or ``import`` inside a function? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ No, you are not allowed to have a ``using`` or ``import`` statement inside a function. If you want to import a module but only use its symbols @@ -102,7 +104,7 @@ inside a specific function or set of functions, you have two options: end - This loads the module Foo and defines a variable ``Foo`` that refers + This loads the module ``Foo`` and defines a variable ``Foo`` that refers to the module, but does not import any of the other symbols from the module into the current namespace. You refer to the ``Foo`` symbols by their qualified names ``Foo.bar`` etc. @@ -119,7 +121,7 @@ inside a specific function or set of functions, you have two options: end using Bar - This imports all the symbols from Foo, but only inside the module Bar. + This imports all the symbols from ``Foo``, but only inside the module ``Bar``. .. _man-slurping-splatting: @@ -134,11 +136,11 @@ what makes the ``...`` operator confusing is that it means two different things depending on context. ``...`` combines many arguments into one argument in function definitions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In the context of function definitions, the ``...`` operator is used to combine many different arguments into a single argument. This use of ``...`` for -combining many different arguments into a single argument is called slurping: +combining many different arguments into a single argument is called slurping:: julia> function printargs(args...) @printf("%s\n", typeof(args)) @@ -164,7 +166,7 @@ In contrast to the use of the ``...`` operator to denote slurping many different arguments into one argument when defining a function, the ``...`` operator is also used to cause a single function argument to be split apart into many different arguments when used in the context of a function call. This -use of ``...`` is called splatting: +use of ``...`` is called splatting:: julia> function threeargs(a, b, c) @printf("a = %s::%s\n", a, typeof(a)) @@ -230,13 +232,13 @@ Certain operations make mathematical sense but result in errors:: in ^ at intfuncs.jl:84 This behavior is an inconvenient consequence of the requirement for -type-stability. In the case of ``sqrt``, most users want +type-stability. In the case of :func:`sqrt`, most users want ``sqrt(2.0)`` to give a real number, and would be unhappy if it produced the complex number ``1.4142135623730951 + 0.0im``. One could -write the ``sqrt`` function to switch to a complex-valued output only -when passed a negative number (which is what ``sqrt`` does in some +write the :func:`sqrt` function to switch to a complex-valued output only +when passed a negative number (which is what :func:`sqrt` does in some other languages), but then the result would not be `type-stable -<#man-type-stable>`_ and the ``sqrt`` function would have poor +<#man-type-stable>`_ and the :func:`sqrt` function would have poor performance. In these and other cases, you can get the result you want by choosing @@ -274,7 +276,7 @@ premium, however, the alternatives are worse. One alternative to consider would be to check each integer operation for overflow and promote results to bigger integer types such as ``Int128`` or -``BigInt`` in the case of overflow. Unfortunately, this introduces major +:class:`BigInt` in the case of overflow. Unfortunately, this introduces major overhead on every integer operation (think incrementing a loop counter) – it requires emitting code to perform run-time overflow checks after arithmetic instructions and branches to handle potential overflows. Worse still, this @@ -284,7 +286,7 @@ generation of efficient code. If you can't count on the results of integer operations being integers, it's impossible to generate fast, simple code the way C and Fortran compilers do. -A variation on this approach, which avoids the appearance of type instability is to merge the ``Int`` and ``BigInt`` types into a single hybrid integer type, that internally changes representation when a result no longer fits into the size of a machine integer. While this superficially avoids type-instability at the level of Julia code, it just sweeps the problem under the rug by foisting all of the same difficulties onto the C code implementing this hybrid integer type. This approach *can* be made to work and can even be made quite fast in many cases, but has several drawbacks. One problem is that the in-memory representation of integers and arrays of integers no longer match the natural representation used by C, Fortran and other languages with native machine integers. Thus, to interoperate with those languages, we would ultimately need to introduce native integer types anyway. Any unbounded representation of integers cannot have a fixed number of bits, and thus cannot be stored inline in an array with fixed-size slots – large integer values will always require separate heap-allocated storage. And of course, no matter how clever a hybrid integer implementation one uses, there are always performance traps – situations where performance degrades unexpectedly. Complex representation, lack of interoperability with C and Fortran, the inability to represent integer arrays without additional heap storage, and unpredictable performance characteristics make even the cleverest hybrid integer implementations a poor choice for high-performance numerical work. +A variation on this approach, which avoids the appearance of type instability is to merge the ``Int`` and :class:`BigInt` types into a single hybrid integer type, that internally changes representation when a result no longer fits into the size of a machine integer. While this superficially avoids type-instability at the level of Julia code, it just sweeps the problem under the rug by foisting all of the same difficulties onto the C code implementing this hybrid integer type. This approach *can* be made to work and can even be made quite fast in many cases, but has several drawbacks. One problem is that the in-memory representation of integers and arrays of integers no longer match the natural representation used by C, Fortran and other languages with native machine integers. Thus, to interoperate with those languages, we would ultimately need to introduce native integer types anyway. Any unbounded representation of integers cannot have a fixed number of bits, and thus cannot be stored inline in an array with fixed-size slots – large integer values will always require separate heap-allocated storage. And of course, no matter how clever a hybrid integer implementation one uses, there are always performance traps – situations where performance degrades unexpectedly. Complex representation, lack of interoperability with C and Fortran, the inability to represent integer arrays without additional heap storage, and unpredictable performance characteristics make even the cleverest hybrid integer implementations a poor choice for high-performance numerical work. An alternative to using hybrid integers or promoting to BigInts is to use saturating integer arithmetic, where adding to the largest integer value @@ -315,7 +317,7 @@ value. This is precisely what Matlab™ does:: -9223372036854775808 -At first blush, this seems reasonable enough since 9223372036854775807 is much closer to 9223372036854775808 than -9223372036854775808 is and integers are still represented with a fixed size in a natural way that is compatible with C and Fortran. Saturated integer arithmetic, however, is deeply problematic. The first and most obvious issue is that this is not the way machine integer arithmetic works, so implementing saturated operations requires emitting instructions after each machine integer operation to check for underflow or overflow and replace the result with ``typemin(Int)`` or ``typemax(Int)`` as appropriate. This alone expands each integer operation from a single, fast instruction into half a dozen instructions, probably including branches. Ouch. But it gets worse – saturating integer arithmetic isn't associative. Consider this Matlab computation:: +At first blush, this seems reasonable enough since 9223372036854775807 is much closer to 9223372036854775808 than -9223372036854775808 is and integers are still represented with a fixed size in a natural way that is compatible with C and Fortran. Saturated integer arithmetic, however, is deeply problematic. The first and most obvious issue is that this is not the way machine integer arithmetic works, so implementing saturated operations requires emitting instructions after each machine integer operation to check for underflow or overflow and replace the result with :func:`typemin(Int) ` or :func:`typemax(Int) ` as appropriate. This alone expands each integer operation from a single, fast instruction into half a dozen instructions, probably including branches. Ouch. But it gets worse – saturating integer arithmetic isn't associative. Consider this Matlab computation:: >> n = int64(2)^62 4611686018427387904 @@ -437,7 +439,7 @@ algebraically reduce multiple operations into fewer equivalent operations. The most reasonable alternative to having integer arithmetic silently overflow is to do checked arithmetic everywhere, raising errors when adds, subtracts, and multiplies overflow, producing values that are not value-correct. In this -[blog post](http://danluu.com/integer-overflow/), Dan Luu analyzes this and +`blog post `_, Dan Luu analyzes this and finds that rather than the trivial cost that this approach should in theory have, it ends up having a substantial cost due to compilers (LLVM and GCC) not gracefully optimizing around the added overflow checks. If this improves diff --git a/doc/manual/functions.rst b/doc/manual/functions.rst index 1cc61222a34b6..a3b78eb3b330d 100644 --- a/doc/manual/functions.rst +++ b/doc/manual/functions.rst @@ -1,5 +1,7 @@ .. _man-functions: +.. currentmodule:: Base + *********** Functions *********** @@ -53,7 +55,7 @@ and can be passed around like any value: There are two other ways that functions can be applied: using special operator syntax for certain function names (see `Operators Are -Functions <#operators-are-functions>`_ below), or with the ``apply`` +Functions <#operators-are-functions>`_ below), or with the :func:`apply` function: .. doctest:: @@ -61,7 +63,7 @@ function: julia> apply(f,2,3) 5 -The ``apply`` function applies its first argument — a function object — +:func:`apply` applies its first argument — a function object — to its remaining arguments. As with variables, Unicode can also be used for function names:: @@ -164,7 +166,7 @@ just as you would any other function: The infix form is exactly equivalent to the function application form — in fact the former is parsed to produce the function call internally. This also means that you can assign and pass around operators such as -``+`` and ``*`` just like you would with other function values: +:func:`+` and :func:`*` just like you would with other function values: .. doctest:: f-plus @@ -182,18 +184,18 @@ Operators With Special Names A few special expressions correspond to calls to functions with non-obvious names. These are: -=================== ============== +=================== ================== Expression Calls -=================== ============== -``[A B C ...]`` ``hcat`` -``[A, B, C, ...]`` ``vcat`` -``[A B; C D; ...]`` ``hvcat`` -``A'`` ``ctranspose`` -``A.'`` ``transpose`` -``1:n`` ``colon`` -``A[i]`` ``getindex`` -``A[i]=x`` ``setindex!`` -=================== ============== +=================== ================== +``[A B C ...]`` :func:`hcat` +``[A, B, C, ...]`` :func:`vcat` +``[A B; C D; ...]`` :func:`hvcat` +``A'`` :func:`ctranspose` +``A.'`` :func:`transpose` +``1:n`` :func:`colon` +``A[i]`` :func:`getindex` +``A[i]=x`` :func:`setindex!` +=================== ================== These functions are included in the ``Base.Operators`` module even though they do not have operator-like names. @@ -218,7 +220,7 @@ without being given a name: This creates an unnamed function taking one argument *x* and returning the value of the polynomial *x*\ ^2 + 2\ *x* - 1 at that value. The primary use for anonymous functions is passing them to functions which take -other functions as arguments. A classic example is the ``map`` function, +other functions as arguments. A classic example is :func:`map`, which applies a function to each value of an array and returns a new array containing the resulting values: @@ -231,7 +233,7 @@ array containing the resulting values: 2.0 This is fine if a named function effecting the transform one wants -already exists to pass as the first argument to ``map``. Often, however, +already exists to pass as the first argument to :func:`map`. Often, however, a ready-to-use, named function does not exist. In these situations, the anonymous function construct allows easy creation of a single-use function object without needing a name: @@ -416,7 +418,7 @@ Optional Arguments In many cases, function arguments have sensible default values and therefore might not need to be passed explicitly in every call. For example, the -library function ``parseint(num,base)`` interprets a string as a number +library function :func:`parseint(num,base) ` interprets a string as a number in some base. The ``base`` argument defaults to ``10``. This behavior can be expressed concisely as:: @@ -526,7 +528,7 @@ Block Syntax for Function Arguments Passing functions as arguments to other functions is a powerful technique, but the syntax for it is not always convenient. Such calls are especially awkward to write when the function argument requires multiple lines. As -an example, consider calling ``map`` on a function with several cases:: +an example, consider calling :func:`map` on a function with several cases:: map(x->begin if x < 0 && iseven(x) @@ -552,20 +554,20 @@ Julia provides a reserved word ``do`` for rewriting this code more clearly:: end The ``do x`` syntax creates an anonymous function with argument ``x`` -and passes it as the first argument to ``map``. Similarly, ``do a,b`` +and passes it as the first argument to :func:`map`. Similarly, ``do a,b`` would create a two-argument anonymous function, and a plain ``do`` would declare that what follows is an anonymous function of the form ``() -> ...``. How these arguments are initialized depends on the "outer" function; -here, ``map`` will sequentially set ``x`` to ``A``, ``B``, ``C``, +here, :func:`map` will sequentially set ``x`` to ``A``, ``B``, ``C``, calling the anonymous function on each, just as would happen in the syntax ``map(func, [A, B, C])``. This syntax makes it easier to use functions to effectively extend the language, since calls look like normal code blocks. There are many -possible uses quite different from ``map``, such as managing system -state. For example, there is a version of ``open`` that runs code +possible uses quite different from :func:`map`, such as managing system +state. For example, there is a version of :func:`open` that runs code ensuring that the opened file is eventually closed:: open("outfile", "w") do io @@ -583,10 +585,10 @@ This is accomplished by the following definition:: end end -In contrast to the ``map`` example, here ``io`` is initialized by the +In contrast to the :func:`map` example, here ``io`` is initialized by the *result* of ``open("outfile", "w")``. The stream is then passed to your anonymous function, which performs the writing; finally, the -``open`` function ensures that the stream is closed after your +:func:`open` function ensures that the stream is closed after your function exits. The ``try/finally`` construct will be described in :ref:`man-control-flow`. diff --git a/doc/manual/integers-and-floating-point-numbers.rst b/doc/manual/integers-and-floating-point-numbers.rst index 1d9b58d0b8a29..5a0c01ba9a2a0 100644 --- a/doc/manual/integers-and-floating-point-numbers.rst +++ b/doc/manual/integers-and-floating-point-numbers.rst @@ -1,5 +1,7 @@ .. _man-integers-and-floating-point-numbers: +.. currentmodule:: Base + ************************************* Integers and Floating-Point Numbers ************************************* @@ -26,31 +28,31 @@ The following are Julia's primitive numeric types: - **Integer types:** -=========== ======= ============== ============== ================== -Type Signed? Number of bits Smallest value Largest value ------------ ------- -------------- -------------- ------------------ -``Int8`` ✓ 8 -2^7 2^7 - 1 -``UInt8`` 8 0 2^8 - 1 -``Int16`` ✓ 16 -2^15 2^15 - 1 -``UInt16`` 16 0 2^16 - 1 -``Int32`` ✓ 32 -2^31 2^31 - 1 -``UInt32`` 32 0 2^32 - 1 -``Int64`` ✓ 64 -2^63 2^63 - 1 -``UInt64`` 64 0 2^64 - 1 -``Int128`` ✓ 128 -2^127 2^127 - 1 -``UInt128`` 128 0 2^128 - 1 -``Bool`` N/A 8 ``false`` (0) ``true`` (1) -=========== ======= ============== ============== ================== +================ ======= ============== ============== ================== +Type Signed? Number of bits Smallest value Largest value +---------------- ------- -------------- -------------- ------------------ +:class:`Int8` ✓ 8 -2^7 2^7 - 1 +:class:`UInt8` 8 0 2^8 - 1 +:class:`Int16` ✓ 16 -2^15 2^15 - 1 +:class:`UInt16` 16 0 2^16 - 1 +:class:`Int32` ✓ 32 -2^31 2^31 - 1 +:class:`UInt32` 32 0 2^32 - 1 +:class:`Int64` ✓ 64 -2^63 2^63 - 1 +:class:`UInt64` 64 0 2^64 - 1 +:class:`Int128` ✓ 128 -2^127 2^127 - 1 +:class:`UInt128` 128 0 2^128 - 1 +:class:`Bool` N/A 8 ``false`` (0) ``true`` (1) +================ ======= ============== ============== ================== - **Floating-point types:** -=========== ========= ============== -Type Precision Number of bits ------------ --------- -------------- -``Float16`` half_ 16 -``Float32`` single_ 32 -``Float64`` double_ 64 -=========== ========= ============== +================ ========= ============== +Type Precision Number of bits +---------------- --------- -------------- +:class:`Float16` half_ 16 +:class:`Float32` single_ 32 +:class:`Float64` double_ 64 +================ ========= ============== .. _half: http://en.wikipedia.org/wiki/Half-precision_floating-point_format .. _single: http://en.wikipedia.org/wiki/Single_precision_floating-point_format @@ -85,7 +87,7 @@ system has a 32-bit architecture or a 64-bit architecture:: julia> typeof(1) Int64 -The Julia internal variable ``WORD_SIZE`` indicates whether the target system +The Julia internal variable :const:`WORD_SIZE` indicates whether the target system is 32-bit or 64-bit.:: # 32-bit system: @@ -96,7 +98,7 @@ is 32-bit or 64-bit.:: julia> WORD_SIZE 64 -Julia also defines the types ``Int`` and ``UInt``, which are aliases for the +Julia also defines the types :class:`Int` and :class:`UInt`, which are aliases for the system's signed and unsigned native integer types respectively.:: # 32-bit system: @@ -155,7 +157,7 @@ hex literals for integer values, one typically is using them to represent a fixed numeric byte sequence, rather than just an integer value. -Recall that the variable ``ans`` is set to the value of the last expression +Recall that the variable :data:`ans` is set to the value of the last expression evaluated in an interactive session. This does not occur when Julia code is run in other ways. @@ -176,7 +178,7 @@ Binary and octal literals are also supported: UInt8 The minimum and maximum representable values of primitive numeric types -such as integers are given by the ``typemin`` and ``typemax`` functions: +such as integers are given by the :func:`typemin` and :func:`typemax` functions: .. doctest:: @@ -197,7 +199,7 @@ such as integers are given by the ``typemin`` and ``typemax`` functions: UInt64: [0,18446744073709551615] UInt128: [0,340282366920938463463374607431768211455] -The values returned by ``typemin`` and ``typemax`` are always of the +The values returned by :func:`typemin` and :func:`typemax` are always of the given argument type. (The above expression uses several features we have yet to introduce, including :ref:`for loops `, :ref:`man-strings`, and :ref:`man-string-interpolation`, @@ -239,9 +241,9 @@ Division errors ~~~~~~~~~~~~~~~ Integer division (the ``div`` function) has two exceptional cases: dividing by -zero, and dividing the lowest negative number (``typemin``) by -1. Both of -these cases throw a ``DivideError``. The remainder and modulus functions -(``rem`` and ``mod``) throw a ``DivideError`` when their second argument is +zero, and dividing the lowest negative number (:func:`typemin`) by -1. Both of +these cases throw a :exc:`DivideError`. The remainder and modulus functions +(``rem`` and ``mod``) throw a :exc:`DivideError` when their second argument is zero. Floating-Point Numbers @@ -405,7 +407,7 @@ floating-point values are the results of certain arithmetic operations: julia> 0 * Inf NaN -The ``typemin`` and ``typemax`` functions also apply to floating-point +The :func:`typemin` and :func:`typemax` functions also apply to floating-point types: .. doctest:: @@ -428,7 +430,7 @@ and so for many purposes it is important to know the distance between two adjacent representable floating-point numbers, which is often known as `machine epsilon `_. -Julia provides the ``eps`` function, which gives the distance between ``1.0`` +Julia provides :func:`eps`, which gives the distance between ``1.0`` and the next larger representable floating-point value: .. doctest:: @@ -443,7 +445,7 @@ and the next larger representable floating-point value: 2.220446049250313e-16 These values are ``2.0^-23`` and ``2.0^-52`` as ``Float32`` and ``Float64`` -values, respectively. The ``eps`` function can also take a +values, respectively. The :func:`eps` function can also take a floating-point value as an argument, and gives the absolute difference between that value and the next representable floating point value. That is, ``eps(x)`` yields a value of the same type as ``x`` such that @@ -471,7 +473,7 @@ number line near zero, and grow sparser exponentially as one moves farther away from zero. By definition, ``eps(1.0)`` is the same as ``eps(Float64)`` since ``1.0`` is a 64-bit floating-point value. -Julia also provides the ``nextfloat`` and ``prevfloat`` functions which return +Julia also provides the :func:`nextfloat` and :func:`prevfloat` functions which return the next largest or smallest representable floating-point number to the argument respectively: : @@ -515,7 +517,7 @@ presented in the `IEEE 754 standard end 1.2 -The default mode used is always ``RoundNearest``, which rounds to the nearest +The default mode used is always :const:`RoundNearest`, which rounds to the nearest representable value, with ties rounded towards the nearest value with an even least significant bit. @@ -560,10 +562,10 @@ Arbitrary Precision Arithmetic To allow computations with arbitrary-precision integers and floating point numbers, Julia wraps the `GNU Multiple Precision Arithmetic Library (GMP) `_ and the `GNU MPFR Library `_, respectively. -The `BigInt` and `BigFloat` types are available in Julia for arbitrary precision +The :class:`BigInt` and :class:`BigFloat` types are available in Julia for arbitrary precision integer and floating point numbers respectively. -Constructors exist to create these types from primitive numerical types, or from ``AbstractString``. +Constructors exist to create these types from primitive numerical types, or from :class:`AbstractString`. Once created, they participate in arithmetic with all other numeric types thanks to Julia's :ref:`type promotion and conversion mechanism `. : @@ -585,7 +587,7 @@ Once created, they participate in arithmetic with all other numeric types thanks 815915283247897734345611269596115894272000000000 However, type promotion between the primitive types above and -`BigInt`/`BigFloat` is not automatic and must be explicitly stated. : +:class:`BigInt`/:class:`BigFloat` is not automatic and must be explicitly stated. .. doctest:: @@ -608,7 +610,7 @@ However, type promotion between the primitive types above and BigInt (constructor with 10 methods) The default precision (in number of bits of the significand) and rounding -mode of `BigFloat` operations can be changed, and all further calculations +mode of :class:`BigFloat` operations can be changed, and all further calculations will take these changes in account: .. doctest:: @@ -728,12 +730,12 @@ Literal zero and one Julia provides functions which return literal 0 and 1 corresponding to a specified type or the type of a given variable. -=========== ===================================================== -Function Description ------------ ----------------------------------------------------- -``zero(x)`` Literal zero of type ``x`` or type of variable ``x`` -``one(x)`` Literal one of type ``x`` or type of variable ``x`` -=========== ===================================================== +====================== ===================================================== +Function Description +---------------------- ----------------------------------------------------- +:func:`zero(x) ` Literal zero of type ``x`` or type of variable ``x`` +:func:`one(x) ` Literal one of type ``x`` or type of variable ``x`` +====================== ===================================================== These functions are useful in :ref:`man-numeric-comparisons` to avoid overhead from unnecessary :ref:`type conversion `. diff --git a/doc/manual/linear-algebra.rst b/doc/manual/linear-algebra.rst index 85b206928393a..9e6dd72f4bec0 100644 --- a/doc/manual/linear-algebra.rst +++ b/doc/manual/linear-algebra.rst @@ -1,3 +1,5 @@ +.. currentmodule:: Base + **************** Linear algebra **************** @@ -13,20 +15,20 @@ The following table summarizes the types of matrix factorizations that have been implemented in Julia. Details of their associated methods can be found in the :ref:`stdlib-linalg` section of the standard library documentation. -=================== =========== -``Cholesky`` `Cholesky factorization `_ -``CholeskyPivoted`` `Pivoted `_ Cholesky factorization -``LU`` `LU factorization `_ -``LUTridiagonal`` LU factorization for Tridiagonal matrices -``UmfpackLU`` LU factorization for sparse matrices (computed by UMFPack) -``QR`` `QR factorization `_ -``QRCompactWY`` Compact WY form of the QR factorization -``QRPivoted`` Pivoted `QR factorization `_ -``Hessenberg`` `Hessenberg decomposition `_ -``Eigen`` `Spectral decomposition `_ -``SVD`` `Singular value decomposition `_ -``GeneralizedSVD`` `Generalized SVD `_ -=================== =========== +======================== ====== +:class:`Cholesky` `Cholesky factorization `_ +:class:`CholeskyPivoted` `Pivoted `_ Cholesky factorization +:class:`LU` `LU factorization `_ +:class:`LUTridiagonal` LU factorization for Tridiagonal matrices +:class:`UmfpackLU` LU factorization for sparse matrices (computed by UMFPack) +:class:`QR` `QR factorization `_ +:class:`QRCompactWY` Compact WY form of the QR factorization +:class:`QRPivoted` Pivoted `QR factorization `_ +:class:`Hessenberg` `Hessenberg decomposition `_ +:class:`Eigen` `Spectral decomposition `_ +:class:`SVD` `Singular value decomposition `_ +:class:`GeneralizedSVD` `Generalized SVD `_ +======================== ====== Special matrices ================ @@ -42,45 +44,39 @@ The following tables summarize the types of special matrices that have been implemented in Julia, as well as whether hooks to various optimized methods for them in LAPACK are available. -+--------------------+-----------------------------------------------------------------------------------+ -| ``Hermitian`` | `Hermitian matrix `_ | -+--------------------+-----------------------------------------------------------------------------------+ -| ``Triangular`` | Upper/lower `triangular matrix `_ | -+--------------------+-----------------------------------------------------------------------------------+ -| ``Tridiagonal`` | `Tridiagonal matrix `_ | -+--------------------+-----------------------------------------------------------------------------------+ -| ``SymTridiagonal`` | Symmetric tridiagonal matrix | -+--------------------+-----------------------------------------------------------------------------------+ -| ``Bidiagonal`` | Upper/lower `bidiagonal matrix `_ | -+--------------------+-----------------------------------------------------------------------------------+ -| ``Diagonal`` | `Diagonal matrix `_ | -+--------------------+-----------------------------------------------------------------------------------+ -| ``UniformScaling`` | `Uniform scaling operator `_ | -+--------------------+-----------------------------------------------------------------------------------+ +======================= ================================================================================== +:class:`Hermitian` `Hermitian matrix `_ +:class:`Triangular` Upper/lower `triangular matrix `_ +:class:`Tridiagonal` `Tridiagonal matrix `_ +:class:`SymTridiagonal` Symmetric tridiagonal matrix +:class:`Bidiagonal` Upper/lower `bidiagonal matrix `_ +:class:`Diagonal` `Diagonal matrix `_ +:class:`UniformScaling` `Uniform scaling operator `_ +======================= ================================================================================== Elementary operations --------------------- -+--------------------+-------+-------+-------+-------+---------------------+ -| Matrix type | ``+`` | ``-`` | ``*`` | ``\`` | Other functions with| -| | | | | | optimized methods | -+--------------------+-------+-------+-------+-------+---------------------+ -| ``Hermitian`` | | | | MV | ``inv``, | -| | | | | | ``sqrtm``, ``expm`` | -+--------------------+-------+-------+-------+-------+---------------------+ -| ``Triangular`` | | | MV | MV | ``inv``, ``det`` | -+--------------------+-------+-------+-------+-------+---------------------+ -| ``SymTridiagonal`` | M | M | MS | MV | ``eigmax/min`` | -+--------------------+-------+-------+-------+-------+---------------------+ -| ``Tridiagonal`` | M | M | MS | MV | | -+--------------------+-------+-------+-------+-------+---------------------+ -| ``Bidiagonal`` | M | M | MS | MV | | -+--------------------+-------+-------+-------+-------+---------------------+ -| ``Diagonal`` | M | M | MV | MV | ``inv``, ``det``, | -| | | | | | ``logdet``, ``/`` | -+--------------------+-------+-------+-------+-------+---------------------+ -| ``UniformScaling`` | M | M | MVS | MVS | ``/`` | -+--------------------+-------+-------+-------+-------+---------------------+ ++-------------------------+-------+-------+-------+-------+--------------------------------+ +| Matrix type | ``+`` | ``-`` | ``*`` | ``\`` | Other functions with | +| | | | | | optimized methods | ++-------------------------+-------+-------+-------+-------+--------------------------------+ +| :class:`Hermitian` | | | | MV | :func:`inv`, | +| | | | | | :func:`sqrtm`, :func:`expm` | ++-------------------------+-------+-------+-------+-------+--------------------------------+ +| :class:`Triangular` | | | MV | MV | :func:`inv`, :func:`det` | ++-------------------------+-------+-------+-------+-------+--------------------------------+ +| :class:`SymTridiagonal` | M | M | MS | MV | :func:`eigmax`, :func:`eigmin` | ++-------------------------+-------+-------+-------+-------+--------------------------------+ +| :class:`Tridiagonal` | M | M | MS | MV | | ++-------------------------+-------+-------+-------+-------+--------------------------------+ +| :class:`Bidiagonal` | M | M | MS | MV | | ++-------------------------+-------+-------+-------+-------+--------------------------------+ +| :class:`Diagonal` | M | M | MV | MV | :func:`inv`, :func:`det`, | +| | | | | | :func:`logdet`, :func:`/` | ++-------------------------+-------+-------+-------+-------+--------------------------------+ +| :class:`UniformScaling` | M | M | MVS | MVS | :func:`/` | ++-------------------------+-------+-------+-------+-------+--------------------------------+ Legend: @@ -95,21 +91,21 @@ Legend: Matrix factorizations --------------------- -+--------------------+--------+---------+-------------+-------------+---------+-------------------+ -| Matrix type | LAPACK | ``eig`` | ``eigvals`` | ``eigvecs`` | ``svd`` | ``svdvals`` | -+====================+========+=========+=============+=============+=========+===================+ -| ``Hermitian`` | HE | | ARI | | | | -+--------------------+--------+---------+-------------+-------------+---------+-------------------+ -| ``Triangular`` | TR | | | | | | -+--------------------+--------+---------+-------------+-------------+---------+-------------------+ -| ``SymTridiagonal`` | ST | A | ARI | AV | | | -+--------------------+--------+---------+-------------+-------------+---------+-------------------+ -| ``Tridiagonal`` | GT | | | | | | -+--------------------+--------+---------+-------------+-------------+---------+-------------------+ -| ``Bidiagonal`` | BD | | | | A | A | -+--------------------+--------+---------+-------------+-------------+---------+-------------------+ -| ``Diagonal`` | DI | | A | | | | -+--------------------+--------+---------+-------------+-------------+---------+-------------------+ ++-------------------------+--------+-------------+-----------------+-----------------+-------------+-----------------+ +| Matrix type | LAPACK | :func:`eig` | :func:`eigvals` | :func:`eigvecs` | :func:`svd` | :func:`svdvals` | ++=========================+========+=============+=================+=================+=============+=================+ +| :class:`Hermitian` | HE | | ARI | | | | ++-------------------------+--------+-------------+-----------------+-----------------+-------------+-----------------+ +| :class:`Triangular` | TR | | | | | | ++-------------------------+--------+-------------+-----------------+-----------------+-------------+-----------------+ +| :class:`SymTridiagonal` | ST | A | ARI | AV | | | ++-------------------------+--------+-------------+-----------------+-----------------+-------------+-----------------+ +| :class:`Tridiagonal` | GT | | | | | | ++-------------------------+--------+-------------+-----------------+-----------------+-------------+-----------------+ +| :class:`Bidiagonal` | BD | | | | A | A | ++-------------------------+--------+-------------+-----------------+-----------------+-------------+-----------------+ +| :class:`Diagonal` | DI | | A | | | | ++-------------------------+--------+-------------+-----------------+-----------------+-------------+-----------------+ Legend: @@ -125,5 +121,5 @@ Legend: The uniform scaling operator ---------------------------- -A ``UniformScaling`` operator represents a scalar times the identity operator, ``λ*I``. The identity operator ``I`` is defined as a constant and is an instance of ``UniformScaling``. The size of these operators are generic and match the other matrix in the binary operations ``+``, ``-``, ``*`` and ``\``. For ``A+I`` and ``A-I`` this means that ``A`` must be square. Multiplication with the identity operator ``I`` is a noop (except for checking that the scaling factor is one) and therefore almost without overhead. +A :class:`UniformScaling` operator represents a scalar times the identity operator, ``λ*I``. The identity operator :class:`I` is defined as a constant and is an instance of :class:`UniformScaling`. The size of these operators are generic and match the other matrix in the binary operations :obj:`+`, :obj:`-`, :obj:`*` and :obj:`\\`. For ``A+I`` and ``A-I`` this means that ``A`` must be square. Multiplication with the identity operator :class: `I` is a noop (except for checking that the scaling factor is one) and therefore almost without overhead. diff --git a/doc/manual/mathematical-operations.rst b/doc/manual/mathematical-operations.rst index fd9477acc945d..e025d5e633233 100644 --- a/doc/manual/mathematical-operations.rst +++ b/doc/manual/mathematical-operations.rst @@ -1,5 +1,7 @@ .. _man-mathematical-operations: +.. currentmodule:: Base + ************************************************** Mathematical Operations and Elementary Functions ************************************************** @@ -145,16 +147,16 @@ Numeric Comparisons Standard comparison operations are defined for all the primitive numeric types: -============= ======================== -Operator Name -============= ======================== -``==`` equality -``!=`` ``≠`` inequality -``<`` less than -``<=`` ``≤`` less than or equal to -``>`` greater than -``>=`` ``≥`` greater than or equal to -============= ======================== +=================== ======================== +Operator Name +=================== ======================== +:obj:`==` equality +:obj:`\!=` :obj:`≠` inequality +:obj:`<` less than +:obj:`<=` :obj:`≤` less than or equal to +:obj:`>` greater than +:obj:`>=` :obj:`≥` greater than or equal to +=================== ======================== Here are some simple examples: @@ -230,16 +232,16 @@ and can cause especial headaches with :ref:`Arrays `: Julia provides additional functions to test numbers for special values, which can be useful in situations like hash key comparisons: -================= ================================== -Function Tests if -================= ================================== -``isequal(x, y)`` ``x`` and ``y`` are identical -``isfinite(x)`` ``x`` is a finite number -``isinf(x)`` ``x`` is infinite -``isnan(x)`` ``x`` is not a number -================= ================================== +=============================== ================================== +Function Tests if +=============================== ================================== +:func:`isequal(x, y) ` ``x`` and ``y`` are identical +:func:`isfinite(x) ` ``x`` is a finite number +:func:`isinf(x) ` ``x`` is infinite +:func:`isnan(x) ` ``x`` is not a number +=============================== ================================== -``isequal`` considers ``NaN``\ s equal to each other: +:func:`isequal` considers ``NaN``\ s equal to each other: .. doctest:: @@ -252,7 +254,7 @@ Function Tests if julia> isequal(NaN,NaN32) true -``isequal`` can also be used to distinguish signed zeros: +:func:`isequal` can also be used to distinguish signed zeros: .. doctest:: @@ -266,10 +268,10 @@ Mixed-type comparisons between signed integers, unsigned integers, and floats can be tricky. A great deal of care has been taken to ensure that Julia does them correctly. -For other types, `isequal` defaults to calling `==`, so if you want to -define equality for your own types then you only need to add a `==` +For other types, :func:`isequal` defaults to calling :func:`==`, so if you want to +define equality for your own types then you only need to add a :func:`==` method. If you define your own equality function, you should probably -define a corresponding `hash` function to ensure that `isequal(x,y)` +define a corresponding :func:`hash` method to ensure that `isequal(x,y)` implies `hash(x) == hash(y)`. Chaining comparisons @@ -285,17 +287,17 @@ comparisons can be arbitrarily chained: true Chaining comparisons is often quite convenient in numerical code. -Chained comparisons use the ``&&`` operator for scalar comparisons, -and the ``&`` operator for elementwise comparisons, which allows them to +Chained comparisons use the :obj:`&&` operator for scalar comparisons, +and the :obj:`&` operator for elementwise comparisons, which allows them to work on arrays. For example, ``0 .< A .< 1`` gives a boolean array whose entries are true where the corresponding elements of ``A`` are between 0 and 1. -The operator ``.<`` is intended for array objects; the operation +The operator :obj:`.<` is intended for array objects; the operation ``A .< B`` is valid only if ``A`` and ``B`` have the same dimensions. The operator returns an array with boolean entries and with the same dimensions as ``A`` and ``B``. Such operators are called *elementwise*; Julia offers a -suite of elementwise operators: ``.*``, ``.+``, etc. Some of the elementwise +suite of elementwise operators: :obj:`.*`, :obj:`.+`, etc. Some of the elementwise operators can take a scalar operand such as the example ``0 .< A .< 1`` in the preceding paragraph. This notation means that the scalar operand should be replicated for each entry of @@ -321,7 +323,7 @@ would be if the expression were written as ``v(1) < v(2) && v(2) <= v(3)``. However, the order of evaluations in a chained comparison is undefined. It is strongly recommended not to use expressions with side effects (such as printing) in chained comparisons. -If side effects are required, the short-circuit ``&&`` operator should +If side effects are required, the short-circuit :obj:`&&` operator should be used explicitly (see :ref:`man-short-circuit-evaluation`). Operator Precedence @@ -359,72 +361,72 @@ such definitions make sense. Rounding functions ~~~~~~~~~~~~~~~~~~ -=============== ==================================== ================= -Function Description Return type -=============== ==================================== ================= -``round(x)`` round ``x`` to the nearest integer ``typeof(x)`` -``round(T, x)`` round ``x`` to the nearest integer ``T`` -``floor(x)`` round ``x`` towards ``-Inf`` ``typeof(x)`` -``floor(T, x)`` round ``x`` towards ``-Inf`` ``T`` -``ceil(x)`` round ``x`` towards ``+Inf`` ``typeof(x)`` -``ceil(T, x)`` round ``x`` towards ``+Inf`` ``T`` -``trunc(x)`` round ``x`` towards zero ``typeof(x)`` -``trunc(T, x)`` round ``x`` towards zero ``T`` -=============== ==================================== ================= +=========================== ================================== ============= +Function Description Return type +=========================== ================================== ============= +:func:`round(x) ` round ``x`` to the nearest integer ``typeof(x)`` +:func:`round(T, x) ` round ``x`` to the nearest integer ``T`` +:func:`floor(x) ` round ``x`` towards ``-Inf`` ``typeof(x)`` +:func:`floor(T, x) ` round ``x`` towards ``-Inf`` ``T`` +:func:`ceil(x) ` round ``x`` towards ``+Inf`` ``typeof(x)`` +:func:`ceil(T, x) ` round ``x`` towards ``+Inf`` ``T`` +:func:`trunc(x) ` round ``x`` towards zero ``typeof(x)`` +:func:`trunc(T, x) ` round ``x`` towards zero ``T`` +=========================== ================================== ============= Division functions ~~~~~~~~~~~~~~~~~~ -=============== ======================================================================= -Function Description -=============== ======================================================================= -``div(x,y)`` truncated division; quotient rounded towards zero -``fld(x,y)`` floored division; quotient rounded towards ``-Inf`` -``cld(x,y)`` ceiling division; quotient rounded towards ``+Inf`` -``rem(x,y)`` remainder; satisfies ``x == div(x,y)*y + rem(x,y)``; sign matches ``x`` -``divrem(x,y)`` returns ``(div(x,y),rem(x,y))`` -``mod(x,y)`` modulus; satisfies ``x == fld(x,y)*y + mod(x,y)``; sign matches ``y`` -``mod2pi(x)`` modulus with respect to 2pi; ``0 <= mod2pi(x) < 2pi`` -``gcd(x,y...)`` greatest common divisor of ``x``, ``y``,...; sign matches ``x`` -``lcm(x,y...)`` least common multiple of ``x``, ``y``,...; sign matches ``x`` -=============== ======================================================================= +============================ ======================================================================= +Function Description +============================ ======================================================================= +:func:`div(x,y)
` truncated division; quotient rounded towards zero +:func:`fld(x,y) ` floored division; quotient rounded towards ``-Inf`` +:func:`cld(x,y) ` ceiling division; quotient rounded towards ``+Inf`` +:func:`rem(x,y) ` remainder; satisfies ``x == div(x,y)*y + rem(x,y)``; sign matches ``x`` +:func:`divrem(x,y) ` returns ``(div(x,y),rem(x,y))`` +:func:`mod(x,y) ` modulus; satisfies ``x == fld(x,y)*y + mod(x,y)``; sign matches ``y`` +:func:`mod2pi(x) ` modulus with respect to 2pi; ``0 <= mod2pi(x) < 2pi`` +:func:`gcd(x,y...) ` greatest common divisor of ``x``, ``y``,...; sign matches ``x`` +:func:`lcm(x,y...) ` least common multiple of ``x``, ``y``,...; sign matches ``x`` +============================ ======================================================================= Sign and absolute value functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -================= =========================================================== -Function Description -================= =========================================================== -``abs(x)`` a positive value with the magnitude of ``x`` -``abs2(x)`` the squared magnitude of ``x`` -``sign(x)`` indicates the sign of ``x``, returning -1, 0, or +1 -``signbit(x)`` indicates whether the sign bit is on (true) or off (false) -``copysign(x,y)`` a value with the magnitude of ``x`` and the sign of ``y`` -``flipsign(x,y)`` a value with the magnitude of ``x`` and the sign of ``x*y`` -================= =========================================================== +================================ =========================================================== +Function Description +================================ =========================================================== +:func:`abs(x) ` a positive value with the magnitude of ``x`` +:func:`abs2(x) ` the squared magnitude of ``x`` +:func:`sign(x) ` indicates the sign of ``x``, returning -1, 0, or +1 +:func:`signbit(x) ` indicates whether the sign bit is on (true) or off (false) +:func:`copysign(x,y) ` a value with the magnitude of ``x`` and the sign of ``y`` +:func:`flipsign(x,y) ` a value with the magnitude of ``x`` and the sign of ``x*y`` +================================ =========================================================== Powers, logs and roots ~~~~~~~~~~~~~~~~~~~~~~ -=================== ============================================================================== -Function Description -=================== ============================================================================== -``sqrt(x)`` ``√x`` the square root of ``x`` -``cbrt(x)`` ``∛x`` the cube root of ``x`` -``hypot(x,y)`` hypotenuse of right-angled triangle with other sides of length ``x`` and ``y`` -``exp(x)`` the natural exponential function at ``x`` -``expm1(x)`` accurate ``exp(x)-1`` for ``x`` near zero -``ldexp(x,n)`` ``x*2^n`` computed efficiently for integer values of ``n`` -``log(x)`` the natural logarithm of ``x`` -``log(b,x)`` the base ``b`` logarithm of ``x`` -``log2(x)`` the base 2 logarithm of ``x`` -``log10(x)`` the base 10 logarithm of ``x`` -``log1p(x)`` accurate ``log(1+x)`` for ``x`` near zero -``exponent(x)`` returns the binary exponent of ``x`` -``significand(x)`` returns the binary significand (a.k.a. mantissa) of a floating-point number ``x`` -=================== ============================================================================== - -For an overview of why functions like ``hypot``, ``expm1``, and ``log1p`` +==================================== ============================================================================== +Function Description +==================================== ============================================================================== +:func:`sqrt(x) ` ``√x`` square root of ``x`` +:func:`cbrt(x) ` ``∛x`` cube root of ``x`` +:func:`hypot(x,y) ` hypotenuse of right-angled triangle with other sides of length ``x`` and ``y`` +:func:`exp(x) ` natural exponential function at ``x`` +:func:`expm1(x) ` accurate ``exp(x)-1`` for ``x`` near zero +:func:`ldexp(x,n) ` ``x*2^n`` computed efficiently for integer values of ``n`` +:func:`log(x) ` natural logarithm of ``x`` +:func:`log(b,x) ` base ``b`` logarithm of ``x`` +:func:`log2(x) ` base 2 logarithm of ``x`` +:func:`log10(x) ` base 10 logarithm of ``x`` +:func:`log1p(x) ` accurate ``log(1+x)`` for ``x`` near zero +:func:`exponent(x) ` binary exponent of ``x`` +:func:`significand(x) ` binary significand (a.k.a. mantissa) of a floating-point number ``x`` +==================================== ============================================================================== + +For an overview of why functions like :func:`hypot`, :func:`expm1`, and :func:`log1p` are necessary and useful, see John D. Cook's excellent pair of blog posts on the subject: `expm1, log1p, erfc `_, @@ -448,11 +450,11 @@ in `radians `_ between the *x*-axis and the point specified by its arguments, interpreted as *x* and *y* coordinates. -Additionally, ``sinpi(x)`` and ``cospi(x)`` are provided for more accurate computations -of ``sin(pi*x)`` and ``cos(pi*x)`` respectively. +Additionally, :func:`sinpi(x) ` and :func:`cospi(x) ` are provided for more accurate computations +of :func:`sin(pi*x) ` and :func:`cos(pi*x) ` respectively. In order to compute trigonometric functions with degrees -instead of radians, suffix the function with ``d``. For example, ``sind(x)`` +instead of radians, suffix the function with ``d``. For example, :func:`sind(x) ` computes the sine of ``x`` where ``x`` is specified in degrees. The complete list of trigonometric functions with degree variants is:: @@ -462,49 +464,49 @@ The complete list of trigonometric functions with degree variants is:: Special functions ~~~~~~~~~~~~~~~~~ -====================================== ============================================================================== -Function Description -====================================== ============================================================================== -``erf(x)`` the `error function `_ at ``x`` -``erfc(x)`` the complementary error function, i.e. the accurate version of ``1-erf(x)`` for large ``x`` -``erfinv(x)`` the inverse function to ``erf`` -``erfcinv(x)`` the inverse function to ``erfc`` -``erfi(x)`` the imaginary error function defined as ``-im * erf(x * im)``, where ``im`` is the imaginary unit -``erfcx(x)`` the scaled complementary error function, i.e. accurate ``exp(x^2) * erfc(x)`` for large ``x`` -``dawson(x)`` the scaled imaginary error function, a.k.a. Dawson function, i.e. accurate ``exp(-x^2) * erfi(x) * sqrt(pi) / 2`` for large ``x`` -``gamma(x)`` the `gamma function `_ at ``x`` -``lgamma(x)`` accurate ``log(gamma(x))`` for large ``x`` -``lfact(x)`` accurate ``log(factorial(x))`` for large ``x``; same as ``lgamma(x+1)`` for ``x > 1``, zero otherwise -``digamma(x)`` the `digamma function `_ (i.e. the derivative of ``lgamma``) at ``x`` -``beta(x,y)`` the `beta function `_ at ``x,y`` -``lbeta(x,y)`` accurate ``log(beta(x,y))`` for large ``x`` or ``y`` -``eta(x)`` the `Dirichlet eta function `_ at ``x`` -``zeta(x)`` the `Riemann zeta function `_ at ``x`` -|airylist| the `Airy Ai function `_ at ``z`` -|airyprimelist| the derivative of the Airy Ai function at ``z`` -``airybi(z)``, ``airy(2,z)`` the `Airy Bi function `_ at ``z`` -``airybiprime(z)``, ``airy(3,z)`` the derivative of the Airy Bi function at ``z`` -``airyx(z)``, ``airyx(k,z)`` the scaled Airy AI function and ``k`` th derivatives at ``z`` -``besselj(nu,z)`` the `Bessel function `_ of the first kind of order ``nu`` at ``z`` -``besselj0(z)`` ``besselj(0,z)`` -``besselj1(z)`` ``besselj(1,z)`` -``besseljx(nu,z)`` the scaled Bessel function of the first kind of order ``nu`` at ``z`` -``bessely(nu,z)`` the `Bessel function `_ of the second kind of order ``nu`` at ``z`` -``bessely0(z)`` ``bessely(0,z)`` -``bessely1(z)`` ``bessely(1,z)`` -``besselyx(nu,z)`` the scaled Bessel function of the second kind of order ``nu`` at ``z`` -``besselh(nu,k,z)`` the `Bessel function `_ of the third kind (a.k.a. Hankel function) of order ``nu`` at ``z``; ``k`` must be either ``1`` or ``2`` -``hankelh1(nu,z)`` ``besselh(nu, 1, z)`` -``hankelh1x(nu,z)`` scaled ``besselh(nu, 1, z)`` -``hankelh2(nu,z)`` ``besselh(nu, 2, z)`` -``hankelh2x(nu,z)`` scaled ``besselh(nu, 2, z)`` -``besseli(nu,z)`` the modified `Bessel function `_ of the first kind of order ``nu`` at ``z`` -``besselix(nu,z)`` the scaled modified Bessel function of the first kind of order ``nu`` at ``z`` -``besselk(nu,z)`` the modified `Bessel function `_ of the second kind of order ``nu`` at ``z`` -``besselkx(nu,z)`` the scaled modified Bessel function of the second kind of order ``nu`` at ``z`` -====================================== ============================================================================== - -.. |airylist| replace:: ``airy(z)``, ``airyai(z)``, ``airy(0,z)`` -.. |airyprimelist| replace:: ``airyprime(z)``, ``airyaiprime(z)``, ``airy(1,z)`` +=================================================== ============================================================================== +Function Description +=================================================== ============================================================================== +:func:`erf(x) ` `error function `_ at ``x`` +:func:`erfc(x) ` complementary error function, i.e. the accurate version of ``1-erf(x)`` for large ``x`` +:func:`erfinv(x) ` inverse function to :func:`erf` +:func:`erfcinv(x) ` inverse function to :func:`erfc` +:func:`erfi(x) ` imaginary error function defined as ``-im * erf(x * im)``, where :const:`im` is the imaginary unit +:func:`erfcx(x) ` scaled complementary error function, i.e. accurate ``exp(x^2) * erfc(x)`` for large ``x`` +:func:`dawson(x) ` scaled imaginary error function, a.k.a. Dawson function, i.e. accurate ``exp(-x^2) * erfi(x) * sqrt(pi) / 2`` for large ``x`` +:func:`gamma(x) ` `gamma function `_ at ``x`` +:func:`lgamma(x) ` accurate ``log(gamma(x))`` for large ``x`` +:func:`lfact(x) ` accurate ``log(factorial(x))`` for large ``x``; same as ``lgamma(x+1)`` for ``x > 1``, zero otherwise +:func:`digamma(x) ` `digamma function `_ (i.e. the derivative of :func:`lgamma`) at ``x`` +:func:`beta(x,y) ` `beta function `_ at ``x,y`` +:func:`lbeta(x,y) ` accurate ``log(beta(x,y))`` for large ``x`` or ``y`` +:func:`eta(x) ` `Dirichlet eta function `_ at ``x`` +:func:`zeta(x) ` `Riemann zeta function `_ at ``x`` +|airylist| `Airy Ai function `_ at ``z`` +|airyprimelist| derivative of the Airy Ai function at ``z`` +:func:`airybi(z) `, ``airy(2,z)`` `Airy Bi function `_ at ``z`` +:func:`airybiprime(z) `, ``airy(3,z)`` derivative of the Airy Bi function at ``z`` +:func:`airyx(z) `, ``airyx(k,z)`` scaled Airy AI function and ``k`` th derivatives at ``z`` +:func:`besselj(nu,z) ` `Bessel function `_ of the first kind of order ``nu`` at ``z`` +:func:`besselj0(z) ` ``besselj(0,z)`` +:func:`besselj1(z) ` ``besselj(1,z)`` +:func:`besseljx(nu,z) ` scaled Bessel function of the first kind of order ``nu`` at ``z`` +:func:`bessely(nu,z) ` `Bessel function `_ of the second kind of order ``nu`` at ``z`` +:func:`bessely0(z) ` ``bessely(0,z)`` +:func:`bessely1(z) ` ``bessely(1,z)`` +:func:`besselyx(nu,z) ` scaled Bessel function of the second kind of order ``nu`` at ``z`` +:func:`besselh(nu,k,z) ` `Bessel function `_ of the third kind (a.k.a. Hankel function) of order ``nu`` at ``z``; ``k`` must be either ``1`` or ``2`` +:func:`hankelh1(nu,z) ` ``besselh(nu, 1, z)`` +:func:`hankelh1x(nu,z) ` scaled ``besselh(nu, 1, z)`` +:func:`hankelh2(nu,z) ` ``besselh(nu, 2, z)`` +:func:`hankelh2x(nu,z) ` scaled ``besselh(nu, 2, z)`` +:func:`besseli(nu,z) ` modified `Bessel function `_ of the first kind of order ``nu`` at ``z`` +:func:`besselix(nu,z) ` scaled modified Bessel function of the first kind of order ``nu`` at ``z`` +:func:`besselk(nu,z) ` modified `Bessel function `_ of the second kind of order ``nu`` at ``z`` +:func:`besselkx(nu,z) ` scaled modified Bessel function of the second kind of order ``nu`` at ``z`` +=================================================== ============================================================================== + +.. |airylist| replace:: :func:`airy(z) `, :func:`airyai(z) `, ``airy(0,z)`` +.. |airyprimelist| replace:: :func:`airyprime(z) `, :func:`airyaiprime(z) `, ``airy(1,z)`` diff --git a/doc/manual/metaprogramming.rst b/doc/manual/metaprogramming.rst index abd858b46e983..5660683e8345e 100644 --- a/doc/manual/metaprogramming.rst +++ b/doc/manual/metaprogramming.rst @@ -22,13 +22,13 @@ all data types and code are represented by normal Julia data structures, so the structure of the program and its types can be explored programmatically just like any other data. -Expressions and Eval --------------------- +Expressions and :func:`eval` +---------------------------- Julia code is represented as a syntax tree built out of Julia data -structures of type ``Expr``. This makes it easy to construct and +structures of type :obj:`Expr`. This makes it easy to construct and manipulate Julia code from within Julia, without generating or parsing -source text. Here is the definition of the ``Expr`` type:: +source text. Here is the definition of the :obj:`Expr` type:: type Expr head::Symbol @@ -38,14 +38,14 @@ source text. Here is the definition of the ``Expr`` type:: The ``head`` is a symbol identifying the kind of expression, and ``args`` is an array of subexpressions, which may be symbols referencing -the values of variables at evaluation time, may be nested ``Expr`` +the values of variables at evaluation time, may be nested :obj:`Expr` objects, or may be actual values of objects. The ``typ`` field is used by type inference to store type annotations, and can generally be ignored. There is special syntax for "quoting" code (analogous to quoting strings) that makes it easy to create expression objects without -explicitly constructing ``Expr`` objects. There are two forms: a short +explicitly constructing :obj:`Expr` objects. There are two forms: a short form for inline expressions using ``:`` followed by a single expression, and a long form for blocks of code, enclosed in ``quote ... end``. Here is an example of the short form used to quote an arithmetic expression: @@ -107,8 +107,8 @@ quoting form: Symbols ~~~~~~~ -When the argument to ``:`` is just a symbol, a ``Symbol`` object results -instead of an ``Expr``: +When the argument to ``:`` is just a symbol, a :obj:`Symbol` object results +instead of an :obj:`Expr`: .. doctest:: @@ -134,7 +134,7 @@ ambiguity in parsing.: julia> :(::) :(::) -``Symbol``\ s can also be created using the ``symbol`` function, which takes +:obj:`Symbol`\ s can also be created using :func:`symbol`, which takes a character or string as its argument: .. doctest:: @@ -145,11 +145,11 @@ a character or string as its argument: julia> symbol("'") :' -``eval`` and Interpolation -~~~~~~~~~~~~~~~~~~~~~~~~~~ +:func:`eval` and Interpolation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Given an expression object, one can cause Julia to evaluate (execute) it -at global scope using the ``eval`` function: +at global scope using :func:`eval`: .. doctest:: @@ -170,9 +170,9 @@ at global scope using the ``eval`` function: julia> eval(ex) 3 -Every :ref:`module ` has its own ``eval`` function that +Every :ref:`module ` has its own :func:`eval` function that evaluates expressions in its global scope. -Expressions passed to ``eval`` are not limited to returning values +Expressions passed to :func:`eval` are not limited to returning values — they can also have side-effects that alter the state of the enclosing module's environment: @@ -193,10 +193,10 @@ module's environment: Here, the evaluation of an expression object causes a value to be assigned to the global variable ``x``. -Since expressions are just ``Expr`` objects which can be constructed +Since expressions are just :obj:`Expr` objects which can be constructed programmatically and then evaluated, one can, from within Julia code, dynamically generate arbitrary code which can then be run using -``eval``. Here is a simple example: +:func:`eval`. Here is a simple example: .. doctest:: @@ -226,7 +226,7 @@ the important distinction between the way ``a`` and ``b`` are used: the symbol ``:b`` is resolved by looking up the value of the variable ``b``. -Constructing ``Expr`` objects like this is powerful, but somewhat +Constructing :obj:`Expr` objects like this is powerful, but somewhat tedious and ugly. Since the Julia parser is already excellent at producing expression objects, Julia allows "splicing" or interpolation of expression objects, prefixed with ``$``, into quoted expressions, @@ -241,7 +241,7 @@ clearly and concisely using interpolation: :(1 + b) This syntax is automatically rewritten to the form above where we -explicitly called ``Expr``. The use of ``$`` for expression +explicitly called :obj:`Expr`. The use of ``$`` for expression interpolation is intentionally reminiscent of :ref:`string interpolation ` and :ref:`command interpolation `. @@ -255,7 +255,7 @@ When a significant amount of repetitive boilerplate code is required, it is common to generate it programmatically to avoid redundancy. In most languages, this requires an extra build step, and a separate program to generate the repetitive code. In Julia, expression interpolation and -eval allow such code generation to take place in the normal course of +:func:`eval` allow such code generation to take place in the normal course of program execution. For example, the following code defines a series of operators on three arguments in terms of their 2-argument forms:: @@ -281,9 +281,9 @@ macro to abbreviate this pattern:: @eval ($op)(a,b,c) = ($op)(($op)(a,b),c) end -The ``@eval`` macro rewrites this call to be precisely equivalent to the +The :obj:`@eval` macro rewrites this call to be precisely equivalent to the above longer versions. For longer blocks of generated code, the -expression argument given to ``@eval`` can be a block:: +expression argument given to :obj:`@eval` can be a block:: @eval begin # multiple lines @@ -331,7 +331,7 @@ expression arguments. Expanders are defined with the ``macro`` keyword:: return resulting_expr end -Here, for example, is a simplified definition of Julia's ``@assert`` macro:: +Here, for example, is a simplified definition of Julia's :obj:`@assert` macro:: macro assert(ex) return :($ex ? nothing : error("Assertion failed: ", $(string(ex)))) @@ -356,7 +356,7 @@ its returned result. This is equivalent to writing:: That is, in the first call, the expression ``:(1==1.0)`` is spliced into the test condition slot, while the value of ``string(:(1==1.0))`` is spliced into the assertion message slot. The entire expression, thus -constructed, is placed into the syntax tree where the ``@assert`` macro +constructed, is placed into the syntax tree where the :obj:`@assert` macro call occurs. Then at execution time, if the test expression evaluates to true, then ``nothing`` is returned, whereas if the test is false, an error is raised indicating the asserted expression that was false. Notice that @@ -364,7 +364,7 @@ it would not be possible to write this as a function, since only the *value* of the condition is available and it would be impossible to display the expression that computed it in the error message. -The actual definition of ``@assert`` in the standard library is more +The actual definition of :obj:`@assert` in the standard library is more complicated. It allows the user to optionally specify their own error message, instead of just printing the failed expression. Just like in functions with a variable number of arguments, this is specified with an @@ -376,7 +376,7 @@ ellipses following the last argument:: return :($ex ? nothing : error($msg)) end -Now ``@assert`` has two modes of operation, depending upon the number of +Now :obj:`@assert` has two modes of operation, depending upon the number of arguments it receives! If there's only one argument, the tuple of expressions captured by ``msgs`` will be empty and it will behave the same as the simpler definition above. But now if the user specifies a second argument, it is @@ -400,13 +400,13 @@ function: Base.error("assertion failed: a should equal b!") end) -There is yet another case that the actual ``@assert`` macro handles: what +There is yet another case that the actual :obj:`@assert` macro handles: what if, in addition to printing "a should equal b," we wanted to print their values? One might naively try to use string interpolation in the custom message, e.g., ``@assert a==b "a ($a) should equal b ($b)!"``, but this won't work as expected with the above macro. Can you see why? Recall from :ref:`string interpolation ` that an -interpolated string is rewritten to a call to the ``string`` function. +interpolated string is rewritten to a call to :func:`string`. Compare: .. doctest:: @@ -431,11 +431,11 @@ Compare: So now instead of getting a plain string in ``msg_body``, the macro is receiving a full expression that will need to be evaluated in order to display as expected. This can be spliced directly into the returned expression -as an argument to the ``string`` call; see `error.jl +as an argument to the :func:`string` call; see `error.jl `_ for the complete implementation. -The ``@assert`` macro makes great use of splicing into quoted expressions +The :obj:`@assert` macro makes great use of splicing into quoted expressions to simplify the manipulation of expressions inside the macro body. @@ -454,7 +454,7 @@ was defined. In this case we need to ensure that all global variables are resolved to the correct module. Julia already has a major advantage over languages with textual macro expansion (like C) in that it only needs to consider the returned expression. All the other variables (such as ``msg`` in -``@assert`` above) follow the :ref:`normal scoping block behavior +:obj:`@assert` above) follow the :ref:`normal scoping block behavior `. To demonstrate these issues, @@ -475,7 +475,7 @@ The macro might look like this:: end Here, we want ``t0``, ``t1``, and ``val`` to be private temporary variables, -and we want ``time`` to refer to the ``time`` function in the standard library, +and we want ``time`` to refer to the :func:`time` function in the standard library, not to any ``time`` variable the user might have (the same applies to ``println``). Imagine the problems that could occur if the user expression ``ex`` also contained assignments to a variable called ``t0``, or defined @@ -487,7 +487,7 @@ variables within a macro result are classified as either local or global. A variable is considered local if it is assigned to (and not declared global), declared local, or used as a function argument name. Otherwise, it is considered global. Local variables are then renamed to be unique -(using the ``gensym`` function, which generates new symbols), and global +(using the :func:`gensym` function, which generates new symbols), and global variables are resolved within the macro definition environment. Therefore both of the above concerns are handled; the macro's locals will not conflict with any user variables, and ``time`` and ``println`` will refer to the @@ -507,7 +507,7 @@ Here the user expression ``ex`` is a call to ``time``, but not the same ``time`` function that the macro uses. It clearly refers to ``MyModule.time``. Therefore we must arrange for the code in ``ex`` to be resolved in the macro call environment. This is done by "escaping" the expression with -the ``esc`` function:: +:func:`esc`:: macro time(ex) ... @@ -572,7 +572,7 @@ directly into the syntax tree:: Not only is the string literal form shorter and far more convenient, but it is also more efficient: since the regular expression is compiled and -the ``Regex`` object is actually created *when the code is compiled*, +the :obj:`Regex` object is actually created *when the code is compiled*, the compilation occurs only once, rather than every time the code is executed. Consider if the regular expression occurs in a loop:: @@ -636,7 +636,7 @@ In addition to the syntax-level introspection utilized in metaprogramming, Julia provides several other runtime reflection capabilities. **Type fields** The names of data type fields (or module members) may be interrogated -using the ``names`` function. For example, given the following type:: +using :func:`names`. For example, given the following type:: type Point x::FloatingPoint @@ -651,8 +651,8 @@ each field in a ``Point`` is stored in the ``types`` field of the Point object:: julia> Point.types (FloatingPoint,Any) -**Subtypes** The *direct* subtypes of any DataType may be listed using -``subtypes(t::DataType)``. For example, the abstract DataType ``FloatingPoint`` +**Subtypes** The *direct* subtypes of any :obj:`DataType` may be listed using +:func:`subtypes`. For example, the abstract :obj:`DataType` :obj:`FloatingPoint` has four (concrete) subtypes:: julia> subtypes(FloatingPoint) @@ -663,23 +663,23 @@ has four (concrete) subtypes:: Float64 Any abstract subtype will also be included in this list, but further subtypes -thereof will not; recursive applications of ``subtypes`` allow to build the +thereof will not; recursive applications of :func:`subtypes` allow to build the full type tree. **Type internals** The internal representation of types is critically important -when interfacing with C code. ``isbits(T::DataType)`` returns true if `T` is +when interfacing with C code. :func:`isbits(T::DataType) ` returns true if `T` is stored with C-compatible alignment. The offsets of each field may be listed -using ``fieldoffsets(T::DataType)``. +using :func:`fieldoffsets(T::DataType) `. **Function methods** The methods of any function may be listed using -``methods(f::Function)``. +:func:`methods`. **Function representations** Functions may be introspected at several levels of representation. The lowered form of a function is available -using ``code_lowered(f::Function, (Args...))``, and the type-inferred lowered form -is available using ``code_typed(f::Function, (Args...))``. +using :func:`code_lowered(f::Function, (Args...)) `, and the type-inferred lowered form +is available using :func:`code_typed(f::Function, (Args...)) `. -Closer to the machine, the LLVM Intermediate Representation of a function is -printed by ``code_llvm(f::Function, (Args...))``, and finally the resulting +Closer to the machine, the LLVM intermediate representation of a function is +printed by :func:`code_llvm(f::Function, (Args...)) `, and finally the resulting assembly instructions (after JIT'ing step) are available using -``code_native(f::Function, (Args...)``. +:func:`code_native(f::Function, (Args...) `. diff --git a/doc/manual/networking-and-streams.rst b/doc/manual/networking-and-streams.rst index 23d7dfe15f44f..c13422b227082 100644 --- a/doc/manual/networking-and-streams.rst +++ b/doc/manual/networking-and-streams.rst @@ -1,20 +1,22 @@ .. _man-networking-and-streams: +.. currentmodule:: Base + ************************ Networking and Streams ************************ Julia provides a rich interface to deal with streaming I/O objects such as -Terminals, Pipes and Tcp Sockets. This interface, though asynchronous at the +terminals, pipes and TCP sockets. This interface, though asynchronous at the system level, is presented in a synchronous manner to the programmer and it is usually unnecessary to think about the underlying asynchronous operation. This -is achieved by making heavy use of Julia cooperative threading (coroutine) +is achieved by making heavy use of Julia cooperative threading (:ref:`coroutine `) functionality. Basic Stream I/O ---------------- -All Julia streams expose at least a `read` and a `write` method, taking the stream as their first argument, e.g.:: +All Julia streams expose at least a :func:`read` and a :func:`write` method, taking the stream as their first argument, e.g.:: julia> write(STDOUT,"Hello World") Hello World @@ -24,7 +26,7 @@ All Julia streams expose at least a `read` and a `write` method, taking the stre '\n' Note that I pressed enter again so that Julia would read the newline. Now, as you can see from this example, the -`write` method takes the data to write as its second argument, while the read method takes the type of the +:func:`write` method takes the data to write as its second argument, while the read method takes the type of the data to be read as the second argument. For example, to read a simple byte array, we could do:: julia> x = zeros(UInt8,4) @@ -60,15 +62,15 @@ or if we had wanted to read the entire line instead:: "abcd\n" Note that depending on your terminal settings, your TTY may be line buffered and might thus require an additional enter before the data -is sent to julia. +is sent to Julia. -To read every line from STDIN you can use the eachline method:: +To read every line from :const:`STDIN` you can use :func:`eachline`:: for line in eachline(STDIN) print("Found $line") end -or if you wanted to read by character instead:: +or :func:`read` if you wanted to read by character instead:: while !eof(STDIN) x = read(STDIN, Char) @@ -78,13 +80,13 @@ or if you wanted to read by character instead:: Text I/O -------- -Note that the write method mentioned above operates on binary streams. In particular, values do not get converted to any canoncical text +Note that the write method mentioned above operates on binary streams. In particular, values do not get converted to any canonical text representation but are written out as is:: julia> write(STDOUT,0x61) a -For Text I/O, use the `print` or `show` methods, depending on your needs (see the standard library reference for a detailed discussion of +For text I/O, use the :func:`print` or :func:`show` methods, depending on your needs (see the standard library reference for a detailed discussion of the difference between the two):: julia> print(STDOUT,0x61) @@ -93,9 +95,9 @@ the difference between the two):: Working with Files ------------------ -Like many other environments, Julia has an `open` function, which takes a filename and returns an `IOStream` object -that you can use to read and write things from the file. For example if we have a file, `hello.txt`, whose contents -are "Hello, World!":: +Like many other environments, Julia has an :func:`open` function, which takes a filename and returns an :class:`IOStream` object +that you can use to read and write things from the file. For example if we have a file, ``hello.txt``, whose contents +are ``Hello, World!``:: julia> f = open("hello.txt") IOStream() @@ -104,7 +106,7 @@ are "Hello, World!":: 1-element Array{Union(ASCIIString,UTF8String),1}: "Hello, World!\n" -If you want to write to a file, you can open it with the write (`"w"`) flag:: +If you want to write to a file, you can open it with the write (``"w"``) flag:: julia> f = open("hello.txt","w") IOStream() @@ -112,16 +114,16 @@ If you want to write to a file, you can open it with the write (`"w"`) flag:: julia> write(f,"Hello again.") 12 -If you examine the contents of `hello.txt` at this point, you will notice that it is empty; nothing has actually -been written to disk yet. This is because the IOStream must be closed before the write is actually flushed to disk:: +If you examine the contents of ``hello.txt`` at this point, you will notice that it is empty; nothing has actually +been written to disk yet. This is because the :class:`IOStream` must be closed before the write is actually flushed to disk:: julia> close(f) -Examining hello.txt again will show it's contents have been changed. +Examining ``hello.txt`` again will show its contents have been changed. -Opening a file, doing something to it's contents, and closing it again is a very common pattern. -To make this easier, there exists another invocation of `open` which takes a function -as it's first argument and filename as it's second, opens the file, calls the function with the file as +Opening a file, doing something to its contents, and closing it again is a very common pattern. +To make this easier, there exists another invocation of :func:`open` which takes a function +as its first argument and filename as its second, opens the file, calls the function with the file as an argument, and then closes it again. For example, given a function:: function read_and_capitalize(f::IOStream) @@ -133,9 +135,9 @@ You can call:: julia> open(read_and_capitalize, "hello.txt") "HELLO AGAIN." -to open `hello.txt`, call `read_and_capitalize on it`, close `hello.txt`. and return the capitalized contents. +to open ``hello.txt``, call ``read_and_capitalize on it``, close ``hello.txt`` and return the capitalized contents. -To avoid even having to define a named function, you can use the `do` syntax, which creates an anonymous +To avoid even having to define a named function, you can use the ``do`` syntax, which creates an anonymous function on the fly:: julia> open("hello.txt") do f @@ -147,7 +149,7 @@ function on the fly:: A simple TCP example -------------------- -Let's jump right in with a simple example involving Tcp Sockets. Let's first create a simple server:: +Let's jump right in with a simple example involving TCP sockets. Let's first create a simple server:: julia> @async begin server = listen(2000) @@ -162,7 +164,7 @@ Let's jump right in with a simple example involving Tcp Sockets. Let's first cre To those familiar with the Unix socket API, the method names will feel familiar, though their usage is somewhat simpler than the raw Unix socket API. The first -call to `listen` will create a server waiting for incoming connections on the +call to :func:`listen` will create a server waiting for incoming connections on the specified port (2000) in this case. The same function may also be used to create various other kinds of servers:: @@ -185,14 +187,14 @@ create various other kinds of servers:: PipeServer(active) Note that the return type of the last invocation is different. This is because -this server does not listen on TCP, but rather on a Named Pipe (Windows -terminology) - also called a Domain Socket (UNIX Terminology). The difference -is subtle and has to do with the `accept` and `connect` methods. The `accept` +this server does not listen on TCP, but rather on a named pipe (Windows) +or domain socket (UNIX). The difference +is subtle and has to do with the :func:`accept` and :func:`connect` methods. The :func:`accept` method retrieves a connection to the client that is connecting on the server we -just created, while the `connect` function connects to a server using the -specified method. The `connect` function takes the same arguments as -`listen`, so, assuming the environment (i.e. host, cwd, etc.) is the same you -should be able to pass the same arguments to `connect` as you did to listen to +just created, while the :func:`connect` function connects to a server using the +specified method. The :func:`connect` function takes the same arguments as +:func:`listen`, so, assuming the environment (i.e. host, cwd, etc.) is the same you +should be able to pass the same arguments to :func:`connect` as you did to listen to establish the connection. So let's try that out (after having created the server above):: julia> connect(2000) @@ -200,9 +202,9 @@ establish the connection. So let's try that out (after having created the server julia> Hello World -As expected we saw "Hello World" printed. So, let's actually analyze what happened behind the scenes. When we called connect, we connect to the server we had just created. Meanwhile, the accept function returns a server-side connection to the newly created socket and prints "Hello World" to indicate that the connection was successful. +As expected we saw "Hello World" printed. So, let's actually analyze what happened behind the scenes. When we called :func:`connect`, we connect to the server we had just created. Meanwhile, the accept function returns a server-side connection to the newly created socket and prints "Hello World" to indicate that the connection was successful. -A great strength of Julia is that since the API is exposed synchronously even though the I/O is actually happening asynchronously, we didn't have to worry callbacks or even making sure that the server gets to run. When we called `connect` the current task waited for the connection to be established and only continued executing after that was done. In this pause, the server task resumed execution (because a connection request was now available), accepted the connection, printed the message and waited for the next client. Reading and writing works in the same way. To see this, consider the following simple echo server:: +A great strength of Julia is that since the API is exposed synchronously even though the I/O is actually happening asynchronously, we didn't have to worry callbacks or even making sure that the server gets to run. When we called :func:`connect` the current task waited for the connection to be established and only continued executing after that was done. In this pause, the server task resumed execution (because a connection request was now available), accepted the connection, printed the message and waited for the next client. Reading and writing works in the same way. To see this, consider the following simple echo server:: julia> @async begin server = listen(2001) @@ -229,14 +231,14 @@ A great strength of Julia is that since the API is exposed synchronously even th Resolving IP Addresses ---------------------- -One of the `connect` methods that does not follow the `listen` methods is `connect(host::ASCIIString,port)`, which will attempt to connect to the host -given by the `host` parameter on the port given by the port parameter. It +One of the :func:`connect` methods that does not follow the :func:`listen` methods is ``connect(host::ASCIIString,port)``, which will attempt to connect to the host +given by the ``host`` parameter on the port given by the port parameter. It allows you to do things like:: julia> connect("google.com",80) TcpSocket(open, 0 bytes waiting) -At the base of this functionality is the getaddrinfo function which will do the appropriate address resolution:: +At the base of this functionality is :func:`getaddrinfo`, which will do the appropriate address resolution:: julia> getaddrinfo("google.com") IPv4(74.125.226.225) diff --git a/doc/manual/noteworthy-differences.rst b/doc/manual/noteworthy-differences.rst index 6c45c754db75f..c98e309759e16 100644 --- a/doc/manual/noteworthy-differences.rst +++ b/doc/manual/noteworthy-differences.rst @@ -144,3 +144,8 @@ Noteworthy differences from Python looping over arrays, the order of the loops should be reversed in Julia relative to `numpy` (see relevant section of :ref:`man-performance-tips`). +- Julia evaluates default values of function arguments every time the method is + invoked (not once when the function is defined as in Python). This means + that function ``f(x=rand()) = x`` returns a new random number every time + it is invoked without argument. On the other hand function + ``g(x=[1,2]) = push!(x,3)`` returns ``[1,2,3]`` every time it is called as ``g()``. diff --git a/doc/manual/packages.rst b/doc/manual/packages.rst index fd24c2fc30507..28378985af109 100644 --- a/doc/manual/packages.rst +++ b/doc/manual/packages.rst @@ -1,5 +1,7 @@ .. _man-packages: +.. currentmodule:: Base + ********** Packages ********** @@ -7,12 +9,12 @@ Julia has a built-in package manager for installing add-on functionality written in Julia. It can also install external libraries using your operating system's standard system for doing so, or by compiling from source. The list of registered Julia packages can be found at ``_. -All package manager commands are found in the ``Pkg`` module, included in Julia's Base install. +All package manager commands are found in the :mod:`Pkg ` module, included in Julia's :mod:`Base` install. Package Status -------------- -The ``Pkg.status()`` function prints out a summary of the state of packages you have installed. +The :func:`Pkg.status` function prints out a summary of the state of packages you have installed. Initially, you'll have no packages installed:: julia> Pkg.status() @@ -20,7 +22,7 @@ Initially, you'll have no packages installed:: INFO: Cloning METADATA from git://github.com/JuliaLang/METADATA.jl No packages installed. -Your package directory is automatically initialized the first time you run a ``Pkg`` command that expects it to exist – which includes ``Pkg.status()``. +Your package directory is automatically initialized the first time you run a :mod:`Pkg ` command that expects it to exist – which includes :func:`Pkg.status`. Here's an example non-trivial set of required and additional packages:: julia> Pkg.status() @@ -31,9 +33,9 @@ Here's an example non-trivial set of required and additional packages:: - NumericExtensions 0.2.17 - Stats 0.2.6 -These packages are all on registered versions, managed by ``Pkg``. +These packages are all on registered versions, managed by :mod:`Pkg `. Packages can be in more complicated states, indicated by annotations to the right of the installed package version; we will explain these states and annotations as we encounter them. -For programmatic usage, ``Pkg.installed()`` returns a dictionary, mapping installed package names to the version of that package which is installed:: +For programmatic usage, :func:`Pkg.installed` returns a dictionary, mapping installed package names to the version of that package which is installed:: julia> Pkg.installed() Dict{ASCIIString,VersionNumber} with 4 entries: @@ -51,10 +53,10 @@ So rather than installing a package, you just add it to the list of requirements In particular, this means that if some package had been installed because it was needed by a previous version of something you wanted, and a newer version doesn't have that requirement anymore, updating will actually remove that package. Your package requirements are in the file ``~/.julia/v0.3/REQUIRE``. -You can edit this file by hand and then call ``Pkg.resolve()`` to install, upgrade or remove packages to optimally satisfy the requirements, or you can do ``Pkg.edit()``, which will open ``REQUIRE`` in your editor (configured via the ``EDITOR`` or ``VISUAL`` environment variables), and then automatically call ``Pkg.resolve()`` afterwards if necessary. -If you only want to add or remove the requirement for a single package, you can also use the non-interactive ``Pkg.add`` and ``Pkg.rm`` commands, which add or remove a single requirement to ``REQUIRE`` and then call ``Pkg.resolve()``. +You can edit this file by hand and then call :func:`Pkg.resolve` to install, upgrade or remove packages to optimally satisfy the requirements, or you can do :func:`Pkg.edit`, which will open ``REQUIRE`` in your editor (configured via the ``EDITOR`` or ``VISUAL`` environment variables), and then automatically call :func:`Pkg.resolve` afterwards if necessary. +If you only want to add or remove the requirement for a single package, you can also use the non-interactive :func:`Pkg.add` and :func:`Pkg.rm` commands, which add or remove a single requirement to ``REQUIRE`` and then call :func:`Pkg.resolve`. -You can add a package to the list of requirements with the ``Pkg.add`` function, and the package and all the packages that it depends on will be installed:: +You can add a package to the list of requirements with the :func:`Pkg.add` function, and the package and all the packages that it depends on will be installed:: julia> Pkg.status() No packages installed. @@ -80,8 +82,8 @@ What this is doing is first adding ``Distributions`` to your ``~/.julia/v0.3/REQ $ cat ~/.julia/v0.3/REQUIRE Distributions -It then runs ``Pkg.resolve()`` using these new requirements, which leads to the conclusion that the ``Distributions`` package should be installed since it is required but not installed. -As stated before, you can accomplish the same thing by editing your ``~/.julia/v0.3/REQUIRE`` file by hand and then running ``Pkg.resolve()`` yourself:: +It then runs :func:`Pkg.resolve` using these new requirements, which leads to the conclusion that the ``Distributions`` package should be installed since it is required but not installed. +As stated before, you can accomplish the same thing by editing your ``~/.julia/v0.3/REQUIRE`` file by hand and then running :func:`Pkg.resolve` yourself:: $ echo UTF16 >> ~/.julia/v0.3/REQUIRE @@ -97,11 +99,11 @@ As stated before, you can accomplish the same thing by editing your ``~/.julia/v - NumericExtensions 0.2.17 - Stats 0.2.6 -This is functionally equivalent to calling ``Pkg.add("UTF16")``, except that ``Pkg.add`` doesn't change ``REQUIRE`` until *after* installation has completed, so if there are problems, ``REQUIRE`` will be left as it was before calling ``Pkg.add``. +This is functionally equivalent to calling :func:`Pkg.add("UTF16") `, except that :func:`Pkg.add` doesn't change ``REQUIRE`` until *after* installation has completed, so if there are problems, ``REQUIRE`` will be left as it was before calling :func:`Pkg.add`. The format of the ``REQUIRE`` file is described in `Requirements Specification`_; it allows, among other things, requiring specific ranges of versions of packages. -When you decide that you don't want to have a package around any more, you can use ``Pkg.rm`` to remove the requirement for it from the ``REQUIRE`` file:: +When you decide that you don't want to have a package around any more, you can use :func:`Pkg.rm` to remove the requirement for it from the ``REQUIRE`` file:: julia> Pkg.rm("Distributions") INFO: Removing Distributions v0.2.7 @@ -120,11 +122,11 @@ When you decide that you don't want to have a package around any more, you can u julia> Pkg.status() No packages installed. -Once again, this is equivalent to editing the ``REQUIRE`` file to remove the line with each package name on it then running ``Pkg.resolve()`` to update the set of installed packages to match. -While ``Pkg.add`` and ``Pkg.rm`` are convenient for adding and removing requirements for a single package, when you want to add or remove multiple packages, you can call ``Pkg.edit()`` to manually change the contents of ``REQUIRE`` and then update your packages accordingly. -``Pkg.edit()`` does not roll back the contents of ``REQUIRE`` if ``Pkg.resolve()`` fails – rather, you have to run ``Pkg.edit()`` again to fix the files contents yourself. +Once again, this is equivalent to editing the ``REQUIRE`` file to remove the line with each package name on it then running :func:`Pkg.resolve` to update the set of installed packages to match. +While :func:`Pkg.add` and :func:`Pkg.rm` are convenient for adding and removing requirements for a single package, when you want to add or remove multiple packages, you can call :func:`Pkg.edit` to manually change the contents of ``REQUIRE`` and then update your packages accordingly. +:func:`Pkg.edit` does not roll back the contents of ``REQUIRE`` if :func:`Pkg.resolve` fails – rather, you have to run :func:`Pkg.edit` again to fix the files contents yourself. -Because the package manager uses git internally to manage the package git repositories, users may run into protocol issues (if behind a firewall, for example), when running ``Pkg.add``. The following command can be run from the command line to tell git to use 'https' instead of the 'git' protocol when cloning repositories:: +Because the package manager uses git internally to manage the package git repositories, users may run into protocol issues (if behind a firewall, for example), when running :func:`Pkg.add`. The following command can be run from the command line to tell git to use 'https' instead of the 'git' protocol when cloning repositories:: git config --global url."https://".insteadOf git:// @@ -133,8 +135,8 @@ Installing Unregistered Packages Julia packages are simply git repositories, clonable via any of the `protocols `_ that git supports, and containing Julia code that follows certain layout conventions. Official Julia packages are registered in the `METADATA.jl `_ repository, available at a well-known location [1]_. -The ``Pkg.add`` and ``Pkg.rm`` commands in the previous section interact with registered packages, but the package manager can install and work with unregistered packages too. -To install an unregistered package, use ``Pkg.clone(url)``, where ``url`` is a git URL from which the package can be cloned:: +The :func:`Pkg.add` and :func:`Pkg.rm` commands in the previous section interact with registered packages, but the package manager can install and work with unregistered packages too. +To install an unregistered package, use :func:`Pkg.clone(url) `, where ``url`` is a git URL from which the package can be cloned:: julia> Pkg.clone("git://example.com/path/to/Package.jl.git") INFO: Cloning Package from git://example.com/path/to/Package.jl.git @@ -157,7 +159,7 @@ Updating Packages ----------------- When package developers publish new registered versions of packages that you're using, you will, of course, want the new shiny versions. -To get the latest and greatest versions of all your packages, just do ``Pkg.update()``:: +To get the latest and greatest versions of all your packages, just do :func:`Pkg.update`:: julia> Pkg.update() INFO: Updating METADATA... @@ -166,14 +168,14 @@ To get the latest and greatest versions of all your packages, just do ``Pkg.upda INFO: Upgrading Stats: v0.2.7 => v0.2.8 The first step of updating packages is to pull new changes to ``~/.julia/v0.3/METADATA`` and see if any new registered package versions have been published. -After this, ``Pkg.update()`` attempts to update packages that are checked out on a branch and not dirty (i.e. no changes have been made to files tracked by git) by pulling changes from the package's upstream repository. +After this, :func:`Pkg.update` attempts to update packages that are checked out on a branch and not dirty (i.e. no changes have been made to files tracked by git) by pulling changes from the package's upstream repository. Upstream changes will only be applied if no merging or rebasing is necessary – i.e. if the branch can be `"fast-forwarded" `_. If the branch cannot be fast-forwarded, it is assumed that you're working on it and will update the repository yourself. Finally, the update process recomputes an optimal set of package versions to have installed to satisfy your top-level requirements and the requirements of "fixed" packages. A package is considered fixed if it is one of the following: -1. **Unregistered:** the package is not in ``METADATA`` – you installed it with ``Pkg.clone``. +1. **Unregistered:** the package is not in ``METADATA`` – you installed it with :func:`Pkg.clone`. 2. **Checked out:** the package repo is on a development branch. 3. **Dirty:** changes have been made to files in the repo. @@ -185,7 +187,7 @@ Checkout, Pin and Free You may want to use the ``master`` version of a package rather than one of its registered versions. There might be fixes or functionality on master that you need that aren't yet published in any registered versions, or you may be a developer of the package and need to make changes on ``master`` or some other development branch. -In such cases, you can do ``Pkg.checkout(pkg)`` to checkout the ``master`` branch of ``pkg`` or ``Pkg.checkout(pkg,branch)`` to checkout some other branch:: +In such cases, you can do :func:`Pkg.checkout(pkg) ` to checkout the ``master`` branch of ``pkg`` or :func:`Pkg.checkout(pkg,branch) ` to checkout some other branch:: julia> Pkg.add("Distributions") INFO: Installing Distributions v0.2.9 @@ -211,14 +213,14 @@ In such cases, you can do ``Pkg.checkout(pkg)`` to checkout the ``master`` branc - NumericExtensions 0.2.17 - Stats 0.2.7 -Immediately after installing ``Distributions`` with ``Pkg.add`` it is on the current most recent registered version – ``0.2.9`` at the time of writing this. -Then after running ``Pkg.checkout("Distributions")``, you can see from the output of ``Pkg.status()`` that ``Distributions`` is on an unregistered version greater than ``0.2.9``, indicated by the "pseudo-version" number ``0.2.9+``. +Immediately after installing ``Distributions`` with :func:`Pkg.add` it is on the current most recent registered version – ``0.2.9`` at the time of writing this. +Then after running :func:`Pkg.checkout("Distributions") `, you can see from the output of :func:`Pkg.status` that ``Distributions`` is on an unregistered version greater than ``0.2.9``, indicated by the "pseudo-version" number ``0.2.9+``. When you checkout an unregistered version of a package, the copy of the ``REQUIRE`` file in the package repo takes precedence over any requirements registered in ``METADATA``, so it is important that developers keep this file accurate and up-to-date, reflecting the actual requirements of the current version of the package. If the ``REQUIRE`` file in the package repo is incorrect or missing, dependencies may be removed when the package is checked out. -This file is also used to populate newly published versions of the package if you use the API that ``Pkg`` provides for this (described below). +This file is also used to populate newly published versions of the package if you use the API that :mod:`Pkg ` provides for this (described below). -When you decide that you no longer want to have a package checked out on a branch, you can "free" it back to the control of the package manager with ``Pkg.free(pkg)``:: +When you decide that you no longer want to have a package checked out on a branch, you can "free" it back to the control of the package manager with :func:`Pkg.free(pkg) `:: julia> Pkg.free("Distributions") INFO: Freeing Distributions... @@ -233,7 +235,7 @@ When you decide that you no longer want to have a package checked out on a branc After this, since the package is on a registered version and not on a branch, its version will be updated as new registered versions of the package are published. -If you want to pin a package at a specific version so that calling ``Pkg.update()`` won't change the version the package is on, you can use the ``Pkg.pin`` function:: +If you want to pin a package at a specific version so that calling :func:`Pkg.update` won't change the version the package is on, you can use the :func:`Pkg.pin` function:: julia> Pkg.pin("Stats") INFO: Creating Stats branch pinned.47c198b1.tmp @@ -246,7 +248,7 @@ If you want to pin a package at a specific version so that calling ``Pkg.update( - Stats 0.2.7 pinned.47c198b1.tmp After this, the ``Stats`` package will remain pinned at version ``0.2.7`` – or more specifically, at commit ``47c198b1``, but since versions are permanently associated a given git hash, this is the same thing. -``Pkg.pin`` works by creating a throw-away branch for the commit you want to pin the package at and then checking that branch out. +:func:`Pkg.pin` works by creating a throw-away branch for the commit you want to pin the package at and then checking that branch out. By default, it pins a package at the current commit, but you can choose a different version by passing a second argument:: julia> Pkg.pin("Stats",v"0.2.5") @@ -261,7 +263,7 @@ By default, it pins a package at the current commit, but you can choose a differ - Stats 0.2.5 pinned.1fd0983b.tmp Now the ``Stats`` package is pinned at commit ``1fd0983b``, which corresponds to version ``0.2.5``. -When you decide to "unpin" a package and let the package manager update it again, you can use ``Pkg.free`` like you would to move off of any branch:: +When you decide to "unpin" a package and let the package manager update it again, you can use :func:`Pkg.free` like you would to move off of any branch:: julia> Pkg.free("Stats") INFO: Freeing Stats... @@ -274,7 +276,7 @@ When you decide to "unpin" a package and let the package manager update it again - NumericExtensions 0.2.17 - Stats 0.2.7 -After this, the ``Stats`` package is managed by the package manager again, and future calls to ``Pkg.update()`` will upgrade it to newer versions when they are published. +After this, the ``Stats`` package is managed by the package manager again, and future calls to :func:`Pkg.update` will upgrade it to newer versions when they are published. The throw-away ``pinned.1fd0983b.tmp`` branch remains in your local ``Stats`` repo, but since git branches are extremely lightweight, this doesn't really matter; if you feel like cleaning them up, you can go into the repo and delete those branches. @@ -311,7 +313,7 @@ Generating a New Package ------------------------ Suppose you want to create a new Julia package called ``FooBar``. -To get started, do ``Pkg.generate(pkg,license)`` where ``pkg`` is the new package name and ``license`` is the name of a license that the package generator knows about:: +To get started, do :func:`Pkg.generate(pkg,license) ` where ``pkg`` is the new package name and ``license`` is the name of a license that the package generator knows about:: julia> Pkg.generate("FooBar","MIT") INFO: Initializing FooBar repo: /Users/stefan/.julia/v0.3/FooBar @@ -350,7 +352,7 @@ This creates the directory ``~/.julia/v0.3/FooBar``, initializes it as a git rep At the moment, the package manager knows about the MIT "Expat" License, indicated by ``"MIT"``, the Simplified BSD License, indicated by ``"BSD"``, and version 2.0 of the Apache Software License, indicated by ``"ASL"``. If you want to use a different license, you can ask us to add it to the package generator, or just pick one of these three and then modify the ``~/.julia/v0.3/PACKAGE/LICENSE.md`` file after it has been generated. -If you created a GitHub account and configured git to know about it, ``Pkg.generate`` will set an appropriate origin URL for you. +If you created a GitHub account and configured git to know about it, :func:`Pkg.generate` will set an appropriate origin URL for you. It will also automatically generate a ``.travis.yml`` file for using the `Travis `_ automated testing service. You will have to enable testing on the Travis website for your package repository, but once you've done that, it will already have working tests. Of course, all the default testing does is verify that ``using FooBar`` in Julia works. @@ -366,7 +368,7 @@ Once you've done this, letting people try out your code is as simple as sending git://github.com/StefanKarpinski/FooBar.jl.git For your package, it will be your GitHub user name and the name of your package, but you get the idea. -People you send this URL to can use ``Pkg.clone`` to install the package and try it out:: +People you send this URL to can use :func:`Pkg.clone` to install the package and try it out:: julia> Pkg.clone("git://github.com/StefanKarpinski/FooBar.jl.git") INFO: Cloning FooBar from git@github.com:StefanKarpinski/FooBar.jl.git @@ -376,7 +378,7 @@ People you send this URL to can use ``Pkg.clone`` to install the package and try Publishing Your Package ----------------------- -Once you've decided that ``FooBar`` is ready to be registered as an official package, you can add it to your local copy of ``METADATA`` using ``Pkg.register``:: +Once you've decided that ``FooBar`` is ready to be registered as an official package, you can add it to your local copy of ``METADATA`` using :func:`Pkg.register`:: julia> Pkg.register("FooBar") INFO: Registering FooBar at git://github.com/StefanKarpinski/FooBar.jl.git @@ -402,7 +404,7 @@ This creates a commit in the ``~/.julia/v0.3/METADATA`` repo:: This commit is only locally visible, however. In order to make it visible to the world, you need to merge your local ``METADATA`` upstream into the official -repo. The ``Pkg.publish()`` command will fork the ``METADATA`` repository on +repo. The :func:`Pkg.publish` command will fork the ``METADATA`` repository on GitHub, push your changes to your fork, and open a pull request:: julia> Pkg.publish() @@ -415,19 +417,19 @@ GitHub, push your changes to your fork, and open a pull request:: https://github.com/StefanKarpinski/METADATA.jl/compare/pull-request/ef45f54b -For various reasons ``Pkg.publish()`` sometimes does not succeed. +For various reasons :func:`Pkg.publish` sometimes does not succeed. In those cases, you may make a pull request on GitHub, which is `not difficult `_. Once the package URL for ``FooBar`` is registered in the official ``METADATA`` repo, people know where to clone the package from, but there still aren't any registered versions available. -This means that ``Pkg.add("FooBar")`` won't work yet since it only installs official versions. -``Pkg.clone("FooBar")`` without having to specify a URL for it. -Moreover, when they run ``Pkg.update()``, they will get the latest version of ``FooBar`` that you've pushed to the repo. +This means that :func:`Pkg.add("FooBar") ` won't work yet since it only installs official versions. +:func:`Pkg.clone("FooBar") ` without having to specify a URL for it. +Moreover, when they run :func:`Pkg.update`, they will get the latest version of ``FooBar`` that you've pushed to the repo. This is a good way to have people test out your packages as you work on them, before they're ready for an official release. Tagging Package Versions ------------------------ -Once you are ready to make an official version your package, you can tag and register it with the ``Pkg.tag`` command:: +Once you are ready to make an official version your package, you can tag and register it with the :func:`Pkg.tag` command:: julia> Pkg.tag("FooBar") INFO: Tagging FooBar v0.0.1 @@ -456,15 +458,15 @@ It also creates a new version entry in your local ``METADATA`` repo for ``FooBar +84b8e266dae6de30ab9703150b3bf771ec7b6285 If there is a ``REQUIRE`` file in your package repo, it will be copied into the appropriate spot in ``METADATA`` when you tag a version. -Package developers should make sure that the ``REQUIRE`` file in their package correctly reflects the requirements of their package, which will automatically flow into the official metadata if you're using ``Pkg.tag``. +Package developers should make sure that the ``REQUIRE`` file in their package correctly reflects the requirements of their package, which will automatically flow into the official metadata if you're using :func:`Pkg.tag`. See the `Requirements Specification <#man-package-requirements>`_ for the full format of ``REQUIRE``. -The ``Pkg.tag`` command takes an optional second argument that is either an explicit version number object like ``v"0.0.1"`` or one of the symbols ``:patch``, ``:minor`` or ``:major``. +The :func:`Pkg.tag` command takes an optional second argument that is either an explicit version number object like ``v"0.0.1"`` or one of the symbols ``:patch``, ``:minor`` or ``:major``. These increment the patch, minor or major version number of your package intelligently. -As with ``Pkg.register``, these changes to ``METADATA`` aren't +As with :func:`Pkg.register`, these changes to ``METADATA`` aren't available to anyone else until they've been included upstream. Again, -use the ``Pkg.publish()`` command, which first makes sure that +use the :func:`Pkg.publish` command, which first makes sure that individual package repos have been tagged, pushes them if they haven't already been, and then opens a pull request to ``METADATA``:: @@ -561,7 +563,7 @@ Examples:: The first condition applies to any system but Windows and the second condition applies to any UNIX system besides OS X. Runtime checks for the current version of Julia can be made using the built-in -``VERSION`` variable, which is of type ``VersionNumber``. Such code is +``VERSION`` variable, which is of type :class:`VersionNumber`. Such code is occasionally necessary to keep track of new or deprecated functionality between various releases of Julia. Examples of runtime checks:: @@ -575,5 +577,3 @@ various releases of Julia. Examples of runtime checks:: See the section on :ref:`version number literals ` for a more complete description. - - diff --git a/doc/manual/parallel-computing.rst b/doc/manual/parallel-computing.rst index 4713d907412d0..c0198ec722202 100644 --- a/doc/manual/parallel-computing.rst +++ b/doc/manual/parallel-computing.rst @@ -1,5 +1,7 @@ .. _man-parallel-computing: +.. currentmodule:: Base + ******************** Parallel Computing ******************** @@ -35,9 +37,9 @@ function on certain arguments on another (possibly the same) process. A remote call returns a remote reference to its result. Remote calls return immediately; the process that made the call proceeds to its next operation while the remote call happens somewhere else. You can -wait for a remote call to finish by calling ``wait`` on its remote +wait for a remote call to finish by calling :func:`wait` on its remote reference, and you can obtain the full value of the result using -``fetch``. You can store a value to a remote reference using ``put!``. +:func:`fetch`. You can store a value to a remote reference using :func:`put!`. Let's try this out. Starting with ``julia -p n`` provides ``n`` worker processes on the local machine. Generally it makes sense for ``n`` to @@ -63,22 +65,22 @@ equal the number of CPU cores on the machine. 1.60401 1.50111 1.17457 1.15741 -The first argument to ``remotecall`` is the index of the process +The first argument to :func:`remotecall` is the index of the process that will do the work. Most parallel programming in Julia does not reference specific processes or the number of processes available, -but ``remotecall`` is considered a low-level interface providing -finer control. The second argument to ``remotecall`` is the function +but :func:`remotecall` is considered a low-level interface providing +finer control. The second argument to :func:`remotecall` is the function to call, and the remaining arguments will be passed to this function. As you can see, in the first line we asked process 2 to construct a 2-by-2 random matrix, and in the second line we asked it to add 1 to it. The result of both calculations is available in the -two remote references, ``r`` and ``s``. The ``@spawnat`` macro +two remote references, ``r`` and ``s``. The :obj:`@spawnat` macro evaluates the expression in the second argument on the process specified by the first argument. Occasionally you might want a remotely-computed value immediately. This typically happens when you read from a remote object to obtain data -needed by the next local operation. The function ``remotecall_fetch`` +needed by the next local operation. The function :func:`remotecall_fetch` exists for this purpose. It is equivalent to ``fetch(remotecall(...))`` but is more efficient. @@ -87,12 +89,12 @@ but is more efficient. julia> remotecall_fetch(2, getindex, r, 1, 1) 0.10824216411304866 -Remember that ``getindex(r,1,1)`` is :ref:`equivalent ` to +Remember that :func:`getindex(r,1,1) ` is :ref:`equivalent ` to ``r[1,1]``, so this call fetches the first element of the remote reference ``r``. -The syntax of ``remotecall`` is not especially convenient. The macro -``@spawn`` makes things easier. It operates on an expression rather than +The syntax of :func:`remotecall` is not especially convenient. The macro +:obj:`@spawn` makes things easier. It operates on an expression rather than a function, and picks where to do the operation for you:: julia> r = @spawn rand(2,2) @@ -106,12 +108,12 @@ a function, and picks where to do the operation for you:: 1.12376292706355074 1.18750497916607167 Note that we used ``1 .+ fetch(r)`` instead of ``1 .+ r``. This is because we -do not know where the code will run, so in general a ``fetch`` might be +do not know where the code will run, so in general a :func:`fetch` might be required to move ``r`` to the process doing the addition. In this -case, ``@spawn`` is smart enough to perform the computation on the -process that owns ``r``, so the ``fetch`` will be a no-op. +case, :obj:`@spawn` is smart enough to perform the computation on the +process that owns ``r``, so the :func:`fetch` will be a no-op. -(It is worth noting that ``@spawn`` is not built-in but defined in Julia +(It is worth noting that :obj:`@spawn` is not built-in but defined in Julia as a :ref:`macro `. It is possible to define your own such constructs.) @@ -120,7 +122,7 @@ Code Availability and Loading Packages -------------------------------------- Your code must be available on any process that runs it. For example, -type the following into the julia prompt:: +type the following into the Julia prompt:: julia> function rand2(dims...) return 2*rand(dims...) @@ -162,7 +164,7 @@ the following code:: Starting julia with ``julia -p 2``, you can use this to verify the following: -- ``include("DummyModule.jl")`` loads the file on just a single process (whichever one executes the statement). +- :func:`include("DummyModule.jl") ` loads the file on just a single process (whichever one executes the statement). - ``using DummyModule`` causes the module to be loaded on all processes; however, the module is brought into scope only on the one executing the statement. - As long as ``DummyModule`` is loaded on process 2, commands like :: @@ -171,12 +173,12 @@ Starting julia with ``julia -p 2``, you can use this to verify the following: allow you to store an object of type ``MyType`` on process 2 even if ``DummyModule`` is not in scope on process 2. -You can force a command to run on all processes using the ``@everywhere`` macro. +You can force a command to run on all processes using the :obj:`@everywhere` macro. Consequently, an easy way to load *and* use a package on all processes is:: @everywhere using DummyModule -``@everywhere`` can also be used to directly define a function on all processes:: +:obj:`@everywhere` can also be used to directly define a function on all processes:: julia> @everywhere id = myid() @@ -187,10 +189,10 @@ A file can also be preloaded on multiple processes at startup, and a driver scri julia -p -L file1.jl -L file2.jl driver.jl -Each process has an associated identifier. The process providing the interactive julia prompt -always has an id equal to 1, as would the julia process running the driver script in the +Each process has an associated identifier. The process providing the interactive Julia prompt +always has an id equal to 1, as would the Julia process running the driver script in the example above. -The processes used by default for parallel operations are referred to as ``workers``. +The processes used by default for parallel operations are referred to as "workers". When there is only one process, process 1 is considered a worker. Otherwise, workers are considered to be all processes other than process 1. @@ -202,11 +204,11 @@ The base Julia installation has in-built support for two types of clusters: ``ssh`` login to start julia worker processes (from the same path as the current host) on the specified machines. -Functions ``addprocs``, ``rmprocs``, ``workers``, and others are available as a programmatic means of +Functions :func:`addprocs`, :func:`rmprocs`, :func:`workers`, and others are available as a programmatic means of adding, removing and querying the processes in a cluster. Other types of clusters can be supported by writing your own custom -``ClusterManager``, as described below in the :ref:`man-clustermanagers` +:class:`ClusterManager`, as described below in the :ref:`man-clustermanagers` section. Data Movement @@ -218,9 +220,9 @@ sent is critical to achieving performance and scalability. To this end, it is important to understand the data movement performed by Julia's various parallel programming constructs. -``fetch`` can be considered an explicit data movement operation, since +:func:`fetch` can be considered an explicit data movement operation, since it directly asks that an object be moved to the local machine. -``@spawn`` (and a few related constructs) also moves data, but this is +:obj:`@spawn` (and a few related constructs) also moves data, but this is not as obvious, hence it can be called an implicit data movement operation. Consider these two approaches to constructing and squaring a random matrix:: @@ -237,7 +239,7 @@ random matrix:: fetch(Bref) The difference seems trivial, but in fact is quite significant due to -the behavior of ``@spawn``. In the first method, a random matrix is +the behavior of :obj:`@spawn`. In the first method, a random matrix is constructed locally, then sent to another process where it is squared. In the second method, a random matrix is both constructed and squared on another process. Therefore the second method sends much less data than @@ -249,10 +251,10 @@ more thought and likely some measurement. For example, if the first process needs matrix ``A`` then the first method might be better. Or, if computing ``A`` is expensive and only the current process has it, then moving it to another process might be unavoidable. Or, if the -current process has very little to do between the ``@spawn`` and +current process has very little to do between the :obj:`@spawn` and ``fetch(Bref)`` then it might be better to eliminate the parallelism altogether. Or imagine ``rand(1000,1000)`` is replaced with a more -expensive operation. Then it might make sense to add another ``@spawn`` +expensive operation. Then it might make sense to add another :obj:`@spawn` statement just for this step. Parallel Map and Loops @@ -261,7 +263,7 @@ Parallel Map and Loops Fortunately, many useful parallel computations do not require data movement. A common example is a Monte Carlo simulation, where multiple processes can handle independent simulation trials simultaneously. We -can use ``@spawn`` to flip coins on two processes. First, write the +can use :obj:`@spawn` to flip coins on two processes. First, write the following function in ``count_heads.jl``:: function count_heads(n) @@ -295,7 +297,7 @@ associative, so that it does not matter what order the operations are performed in. Notice that our use of this pattern with ``count_heads`` can be -generalized. We used two explicit ``@spawn`` statements, which limits +generalized. We used two explicit :obj:`@spawn` statements, which limits the parallelism to two processes. To run on any number of processes, we can use a *parallel for loop*, which can be written in Julia like this:: @@ -342,26 +344,26 @@ vector ``a`` shared by all processes. As you could see, the reduction operator can be omitted if it is not needed. In that case, the loop executes asynchronously, i.e. it spawns independent -tasks on all available workers and returns an array of ``RemoteRef`` +tasks on all available workers and returns an array of :class:`RemoteRef` immediately without waiting for completion. -The caller can wait for the ``RemoteRef`` completions at a later -point by calling ``fetch`` on them, or wait for completion at the end of the -loop by prefixing it with ``@sync``, like ``@sync @parallel for``. +The caller can wait for the :class:`RemoteRef` completions at a later +point by calling :func:`fetch` on them, or wait for completion at the end of the +loop by prefixing it with :obj:`@sync`, like ``@sync @parallel for``. In some cases no reduction operator is needed, and we merely wish to apply a function to all integers in some range (or, more generally, to all elements in some collection). This is another useful operation -called *parallel map*, implemented in Julia as the ``pmap`` function. +called *parallel map*, implemented in Julia as the :func:`pmap` function. For example, we could compute the singular values of several large random matrices in parallel as follows:: M = {rand(1000,1000) for i=1:10} pmap(svd, M) -Julia's ``pmap`` is designed for the case where each function call does +Julia's :func:`pmap` is designed for the case where each function call does a large amount of work. In contrast, ``@parallel for`` can handle situations where each iteration is tiny, perhaps merely summing two -numbers. Only worker processes are used by both ``pmap`` and ``@parallel for`` +numbers. Only worker processes are used by both :func:`pmap` and ``@parallel for`` for the parallel computation. In case of ``@parallel for``, the final reduction is done on the calling process. @@ -376,7 +378,7 @@ Scheduling Julia's parallel programming platform uses :ref:`man-tasks` to switch among multiple computations. Whenever code performs a communication operation -like ``fetch`` or ``wait``, the current task is suspended and a +like :func:`fetch` or :func:`wait`, the current task is suspended and a scheduler picks another task to run. A task is restarted when the event it is waiting for completes. @@ -398,7 +400,7 @@ If one process handles both 800x800 matrices and another handles both 600x600 matrices, we will not get as much scalability as we could. The solution is to make a local task to "feed" work to each process when it completes its current task. This can be seen in the implementation of -``pmap``:: +:func:`pmap`:: function pmap(f, lst) np = nprocs() # determine the number of processes available @@ -426,18 +428,18 @@ it completes its current task. This can be seen in the implementation of results end -``@async`` is similar to ``@spawn``, but only runs tasks on the +:obj:`@async` is similar to :obj:`@spawn`, but only runs tasks on the local process. We use it to create a "feeder" task for each process. Each task picks the next index that needs to be computed, then waits for its process to finish, then repeats until we run out of indexes. Note that the feeder tasks do not begin to execute until the main task -reaches the end of the ``@sync`` block, at which point it surrenders +reaches the end of the :obj:`@sync` block, at which point it surrenders control and waits for all the local tasks to complete before returning from the function. The feeder tasks are able to share state via -``nextidx()`` because they all run on the same process. No locking is +:func:`nextidx` because they all run on the same process. No locking is required, since the threads are scheduled cooperatively and not preemptively. This means context switches only occur at well-defined -points: in this case, when ``remotecall_fetch`` is called. +points: in this case, when :func:`remotecall_fetch` is called. Distributed Arrays ------------------ @@ -450,10 +452,10 @@ on one machine. Each process operates on the part of the array it owns, providing a ready answer to the question of how a program should be divided among machines. -Julia distributed arrays are implemented by the ``DArray`` type. A -``DArray`` has an element type and dimensions just like an ``Array``. -A ``DArray`` can also use arbitrary array-like types to represent the local -chunks that store actual data. The data in a ``DArray`` is distributed by +Julia distributed arrays are implemented by the :class:`DArray` type. A +:class:`DArray` has an element type and dimensions just like an :class:`Array`. +A :class:`DArray` can also use arbitrary array-like types to represent the local +chunks that store actual data. The data in a :class:`DArray` is distributed by dividing the index space into some number of blocks in each dimension. Common kinds of arrays can be constructed with functions beginning with @@ -463,7 +465,7 @@ Common kinds of arrays can be constructed with functions beginning with dones(100,100,10) drand(100,100,10) drandn(100,100,10) - dfill(x, 100,100,10) + dfill(x,100,100,10) In the last case, each element will be initialized to the specified value ``x``. These functions automatically pick a distribution for you. @@ -474,8 +476,8 @@ data should be distributed:: The second argument specifies that the array should be created on the first four workers. When dividing data among a large number of processes, -one often sees diminishing returns in performance. Placing ``DArray``\ s -on a subset of processes allows multiple ``DArray`` computations to +one often sees diminishing returns in performance. Placing :class:`DArray`\ s +on a subset of processes allows multiple :class:`DArray` computations to happen at once, with a higher ratio of work to communication on each process. @@ -486,24 +488,24 @@ dimension will be divided into 4 pieces. Therefore each local chunk will be of size ``(100,25)``. Note that the product of the distribution array must equal the number of processes. -``distribute(a::Array)`` converts a local array to a distributed array. +:func:`distribute(a::Array) ` converts a local array to a distributed array. -``localpart(a::DArray)`` obtains the locally-stored portion -of a ``DArray``. +:func:`localpart(a::DArray) ` obtains the locally-stored portion +of a :class:`DArray`. -``localindexes(a::DArray)`` gives a tuple of the index ranges owned by the +:func:`localindexes(a::DArray) ` gives a tuple of the index ranges owned by the local process. -``convert(Array, a::DArray)`` brings all the data to the local process. +:func:`convert(Array, a::DArray) ` brings all the data to the local process. -Indexing a ``DArray`` (square brackets) with ranges of indexes always -creates a ``SubArray``, not copying any data. +Indexing a :class:`DArray` (square brackets) with ranges of indexes always +creates a :class:`SubArray`, not copying any data. Constructing Distributed Arrays ------------------------------- -The primitive ``DArray`` constructor has the following somewhat elaborate signature:: +The primitive :func:`DArray ` constructor has the following somewhat elaborate signature:: DArray(init, dims[, procs, dist]) @@ -517,12 +519,12 @@ distributed array should be divided into in each dimension. The last two arguments are optional, and defaults will be used if they are omitted. -As an example, here is how to turn the local array constructor ``fill`` +As an example, here is how to turn the local array constructor :func:`fill` into a distributed array constructor:: dfill(v, args...) = DArray(I->fill(v, map(length,I)), args...) -In this case the ``init`` function only needs to call ``fill`` with the +In this case the ``init`` function only needs to call :func:`fill` with the dimensions of the local piece it is creating. Distributed Array Operations @@ -560,10 +562,10 @@ following code accomplishes this:: As you can see, we use a series of indexing expressions to fetch data into a local array ``old``. Note that the ``do`` block syntax is -convenient for passing ``init`` functions to the ``DArray`` constructor. +convenient for passing ``init`` functions to the :class:`DArray` constructor. Next, the serial function ``life_rule`` is called to apply the update rules -to the data, yielding the needed ``DArray`` chunk. Nothing about ``life_rule`` -is ``DArray``\ -specific, but we list it here for completeness:: +to the data, yielding the needed :class:`DArray` chunk. Nothing about ``life_rule`` +is :class:`DArray`\ -specific, but we list it here for completeness:: function life_rule(old) m, n = size(old) @@ -585,22 +587,22 @@ Shared Arrays (Experimental) ----------------------------------------------- Shared Arrays use system shared memory to map the same array across -many processes. While there are some similarities to a ``DArray``, -the behavior of a ``SharedArray`` is quite different. In a ``DArray``, +many processes. While there are some similarities to a :class:`DArray`, +the behavior of a :class:`SharedArray` is quite different. In a :class:`DArray`, each process has local access to just a chunk of the data, and no two -processes share the same chunk; in contrast, in a ``SharedArray`` each +processes share the same chunk; in contrast, in a :class:`SharedArray` each "participating" process has access to the entire array. A -``SharedArray`` is a good choice when you want to have a large amount +:class:`SharedArray` is a good choice when you want to have a large amount of data jointly accessible to two or more processes on the same machine. -``SharedArray`` indexing (assignment and accessing values) works just +:class:`SharedArray` indexing (assignment and accessing values) works just as with regular arrays, and is efficient because the underlying memory is available to the local process. Therefore, most algorithms work -naturally on ``SharedArrays``, albeit in single-process mode. In -cases where an algorithm insists on an ``Array`` input, the underlying -array can be retrieved from a ``SharedArray`` by calling ``sdata(S)``. -For other ``AbstractArray`` types, ``sdata`` just returns the object -itself, so it's safe to use ``sdata`` on any Array-type object. +naturally on :class:`SharedArray`\ s, albeit in single-process mode. In +cases where an algorithm insists on an :class:`Array` input, the underlying +array can be retrieved from a :class:`SharedArray` by calling :func:`sdata`. +For other :class:`AbstractArray` types, ``sdata`` just returns the object +itself, so it's safe to use :func:`sdata` on any Array-type object. The constructor for a shared array is of the form:: @@ -640,7 +642,7 @@ Here's a brief example:: 2 3 3 4 2 7 4 4 -``localindexes`` provides disjoint one-dimensional ranges of indexes, +:func:`localindexes` provides disjoint one-dimensional ranges of indexes, and is sometimes convenient for splitting up tasks among processes. You can, of course, divide the work any way you wish:: @@ -674,21 +676,21 @@ ClusterManagers Julia worker processes can also be spawned on arbitrary machines, enabling Julia's natural parallelism to function quite transparently -in a cluster environment. The ``ClusterManager`` interface provides a +in a cluster environment. The :class:`ClusterManager` interface provides a way to specify a means to launch and manage worker processes. Thus, a custom cluster manager would need to: -- be a subtype of the abstract ``ClusterManager`` -- implement ``launch``, a method responsible for launching new workers -- implement ``manage``, which is called at various events during a worker's lifetime +- be a subtype of the abstract :class:`ClusterManager` +- implement :func:`launch`, a method responsible for launching new workers +- implement :func:`manage`, which is called at various events during a worker's lifetime Julia provides two in-built cluster managers: -- ``LocalManager`` used when ``addprocs()`` or ``addprocs(::Integer)`` are called -- ``SSHManager`` used when ``addprocs(::Array)`` is called with a list of hostnames +- :class:`LocalManager`, used when :func:`addprocs` or :func:`addprocs(::Integer) ` are called +- :class:`SSHManager`, used when :func:`addprocs(::Array) ` is called with a list of hostnames -``addprocs(manager::FooManager)`` requires ``FooManager`` to implement:: +:func:`addprocs(manager::FooManager) ` requires ``FooManager`` to implement:: function launch(manager::FooManager, params::Dict, launched::Array, c::Condition) ... @@ -699,7 +701,7 @@ Julia provides two in-built cluster managers: end -As an example let us see how the ``LocalManager``, the manager responsible for +As an example let us see how the :class:`LocalManager`, the manager responsible for starting workers on the same host, is implemented:: immutable LocalManager <: ClusterManager @@ -714,54 +716,55 @@ starting workers on the same host, is implemented:: ... end -The ``launch`` method takes the following arguments: +The :func:`launch` method takes the following arguments: - - ``manager::ClusterManager`` - the cluster manager ``addprocs`` is called with - - ``params::Dict`` - all the keyword arguments passed to ``addprocs`` + - ``manager::ClusterManager`` - the cluster manager :func:`addprocs` is called with + - ``params::Dict`` - all the keyword arguments passed to :func:`addprocs` - ``launched::Array`` - the array to append one or more ``WorkerConfig`` objects to - ``c::Condition`` - the condition variable to be notified as and when workers are launched -The ``launch`` method is called asynchronously in a separate task. The termination of this task -signals that all requested workers have been launched. Hence the ``launch`` function MUST exit as soon -as all the requested workers have been launched. The julia worker MUST be launched with a ``--worker`` +The :func:`launch` method is called asynchronously in a separate task. The termination of this task +signals that all requested workers have been launched. Hence the :func:`launch` function MUST exit as soon +as all the requested workers have been launched. The Julia worker MUST be launched with a ``--worker`` argument. Optionally ``--bind-to bind_addr[:port]`` may also be specified to enable other workers to connect to it at the specified ``bind_addr`` and ``port``. Useful for multi-homed hosts. -For every worker launched, the ``launch`` method must add a ``WorkerConfig``object with appropriate -fields initialized to ``launched``:: +For every worker launched, the :func:`launch` method must add a :clas`WorkerConfig` +object with appropriate fields initialized to ``launched`` :: -type WorkerConfig - # Common fields relevant to all cluster managers - io::Nullable{IO} - host::Nullable{AbstractString} - port::Nullable{Integer} + type WorkerConfig + # Common fields relevant to all cluster managers + io::Nullable{IO} + host::Nullable{AbstractString} + port::Nullable{Integer} - # Used when launching additional workers at a host - count::Nullable{Union(Int, Symbol)} - exeflags::Nullable{Cmd} + # Used when launching additional workers at a host + count::Nullable{Union(Int, Symbol)} + exeflags::Nullable{Cmd} - # External cluster managers can use this to store information at a per-worker level - # Can be a dict if multiple fields need to be stored. - userdata::Nullable{Any} + # External cluster managers can use this to store information at a per-worker level + # Can be a dict if multiple fields need to be stored. + userdata::Nullable{Any} - # SSHManager / SSH tunnel connections to workers - tunnel::Nullable{Bool} - bind_addr::Nullable{AbstractString} - sshflags::Nullable{Cmd} - max_parallel::Nullable{Integer} + # SSHManager / SSH tunnel connections to workers + tunnel::Nullable{Bool} + bind_addr::Nullable{AbstractString} + sshflags::Nullable{Cmd} + max_parallel::Nullable{Integer} - ..... -end + ..... + end -Most of the fields in ``WorkerConfig`` are used by the inbuilt managers. +Most of the fields in :class:`WorkerConfig` are used by the inbuilt managers. Custom cluster managers would typically specify only ``io`` or ``host`` / ``port``: -If ``io`` is specified, it is used to read host/port information. A julia worker prints out -its bind address and port at startup. This allows julia workers to listen on any free port -available instead of requiring worker ports to be configured manually. +If ``io`` is specified, it is used to read host/port information. A Julia +worker prints out its bind address and port at startup. This allows Julia +workers to listen on any free port available instead of requiring worker ports +to be configured manually. -If ``io`` is not specfied, ``host`` and ``port`` are used to connect. +If ``io`` is not specified, ``host`` and ``port`` are used to connect. ``count`` and ``exeflags`` are relevant for launching additional workers from a worker. For example, a cluster manager may launch a single worker per node, and use that to launch @@ -776,13 +779,13 @@ required to connect to the workers from the master process. -``manage(manager::FooManager, id::Integer, config::WorkerConfig, op::Symbol)`` is called at different +:func:`manage(manager::FooManager, id::Integer, config::WorkerConfig, op::Symbol) ` is called at different times during the worker's lifetime with different ``op`` values: - with ``:register``/``:deregister`` when a worker is added / removed from the Julia worker pool. - with ``:interrupt`` when ``interrupt(workers)`` is called. The - ``ClusterManager`` should signal the appropriate worker with an + :class:`ClusterManager` should signal the appropriate worker with an interrupt signal. - with ``:finalize`` for cleanup purposes. diff --git a/doc/manual/performance-tips.rst b/doc/manual/performance-tips.rst index 4c092580229c7..68f985d6db318 100644 --- a/doc/manual/performance-tips.rst +++ b/doc/manual/performance-tips.rst @@ -1,5 +1,7 @@ .. _man-performance-tips: +.. currentmodule:: Base + ****************** Performance Tips ****************** @@ -15,7 +17,7 @@ at any point. This makes it difficult for the compiler to optimize code using global variables. Variables should be local, or passed as arguments to functions, whenever possible. -Any code that is performance-critical or being benchmarked should be +Any code that is performance critical or being benchmarked should be inside a function. We find that global names are frequently constants, and declaring them @@ -33,10 +35,10 @@ Writing functions is better style. It leads to more reusable code and clarifies what steps are being done, and what their inputs and outputs are. -Measure performance with ``@time`` and pay attention to memory allocation -------------------------------------------------------------------------- +Measure performance with :obj:`@time` and pay attention to memory allocation +---------------------------------------------------------------------------- -The most useful tool for measuring performance is the ``@time`` macro. +The most useful tool for measuring performance is the :obj:`@time` macro. The following example illustrates good working style:: julia> function f(n) @@ -57,12 +59,12 @@ The following example illustrates good working style:: 2.5000025e11 On the first call (``@time f(1)``), ``f`` gets compiled. (If you've -not yet used ``@time`` in this session, it will also compile functions +not yet used :obj:`@time` in this session, it will also compile functions needed for timing.) You should not take the results of this run seriously. For the second run, note that in addition to reporting the time, it also indicated that a large amount of memory was allocated. -This is the single biggest advantage of ``@time`` vs. functions like -``tic`` and ``toc``, which only report time. +This is the single biggest advantage of :obj:`@time` vs. functions like +:func:`tic` and :func:`toc`, which only report time. Unexpected memory allocation is almost always a sign of some problem with your code, usually a problem with type-stability. Consequently, @@ -102,23 +104,21 @@ diagnose problems and improve the performance of your code: `_ package can help you visualize your profiling results. -- Unexpectedly-large memory allocations---as reported by ``@time``, - ``@allocated``, or the profiler (through calls to the +- Unexpectedly-large memory allocations---as reported by :obj:`@time`, + :obj:`@allocated`, or the profiler (through calls to the garbage-collection routines)---hint that there might be issues with your code. If you don't see another reason for the allocations, - suspect a type problem. You can also start julia with the + suspect a type problem. You can also start Julia with the ``--track-allocation=user`` option and examine the resulting ``*.mem`` files to see information about where those allocations occur. See :ref:`stdlib-track-allocation`. -- The `TypeCheck `_ - package can help identify certain kinds of type problems. A more - laborious but comprehensive tool is ``code_typed``. Look - particularly for variables that have type ``Any`` (in the header) or - statements declared as ``Union`` types. Such problems can usually - be fixed using the tips below. +- ``@code_warntype`` generates a representation of your code that can + be helpful in finding expressions that result in type uncertainty. + See :ref:`man-code-warntype` below. -- The `Lint `_ package can also +- The `Lint `_ and `TypeCheck + `_ packages can also warn you of certain types of programming errors. @@ -136,11 +136,11 @@ Consider the following:: push!(a, f) end -Because ``a`` is a an array of abstract type ``Real``, it must be able -to hold any Real value. Since ``Real`` objects can be of arbitrary +Because ``a`` is a an array of abstract type :class:`Real`, it must be able +to hold any Real value. Since :class:`Real` objects can be of arbitrary size and structure, ``a`` must be represented as an array of pointers to -individually allocated ``Real`` objects. Because ``f`` will always be -a ``Float64``, we should instead, use:: +individually allocated :class:`Real` objects. Because ``f`` will always be +a :class:`Float64`, we should instead, use:: a = Float64[] # typeof(a) = Array{Float64,1} @@ -189,7 +189,7 @@ share this knowledge with the compiler:: end Here, we happened to know that the first element of ``a`` would be an -``Int32``. Making an annotation like this has the added benefit that it +:class:`Int32`. Making an annotation like this has the added benefit that it will raise a run-time error if the value is not of the expected type, potentially catching certain bugs earlier. @@ -246,14 +246,14 @@ of the same type. Consider the following definition:: pos(x) = x < 0 ? 0 : x Although this seems innocent enough, the problem is that ``0`` is an -integer (of type ``Int``) and ``x`` might be of any type. Thus, +integer (of type :class:`Int`) and ``x`` might be of any type. Thus, depending on the value of ``x``, this function might return a value of either of two types. This behavior is allowed, and may be desirable in some cases. But it can easily be fixed as follows:: pos(x) = x < 0 ? zero(x) : x -There is also a ``one`` function, and a more general ``oftype(x,y)`` +There is also a :func:`one` function, and a more general :func:`oftype(x,y) ` function, which returns ``y`` converted to the type of ``x``. Avoid changing the type of a variable @@ -271,7 +271,7 @@ repeatedly within a function:: end Local variable ``x`` starts as an integer, and after one loop iteration -becomes a floating-point number (the result of the ``/`` operator). This +becomes a floating-point number (the result of :obj:`/` operator). This makes it more difficult for the compiler to optimize the body of the loop. There are several possible fixes: @@ -362,13 +362,12 @@ that looping will be faster if the inner-most loop index is the first to appear in a slice expression. Consider the following contrived example. Imagine we wanted to write a -function that accepts a ``Vector`` and and returns a square ``Matrix`` +function that accepts a :obj:`Vector` and returns a square :obj:`Matrix` with either the rows or the columns filled with copies of the input vector. Assume that it is not important whether rows or columns are filled with these copies (perhaps the rest of the code can be easily adapted accordingly). We could conceivably do this in at least four ways -(in addition to the recommended call to the built-in function -``repmat``):: +(in addition to the recommended call to the built-in :func:`repmat`):: function copy_cols{T}(x::Vector{T}) n = size(x, 1) @@ -421,7 +420,7 @@ by ``1`` input vector:: Notice that ``copy_cols`` is much faster than ``copy_rows``. This is expected because ``copy_cols`` respects the column-based memory layout -of the ``Matrix`` and fills it one column at a time. Additionally, +of the :obj:`Matrix` and fills it one column at a time. Additionally, ``copy_col_row`` is much faster than ``copy_row_col`` because it follows our rule of thumb that the first element to appear in a slice expression should be coupled with the inner-most loop. @@ -437,7 +436,7 @@ allocation and its converse, garbage collection, are substantial bottlenecks. Sometimes you can circumvent the need to allocate memory on each -function call by pre-allocating the output. As a +function call by preallocating the output. As a trivial example, compare :: @@ -473,7 +472,7 @@ with end y end - + Timing results:: julia> @time loopinc() @@ -484,9 +483,9 @@ Timing results:: elapsed time: 0.078639163 seconds (144 bytes allocated) 50000015000000 -Pre-allocation has other advantages, for example by allowing the +Preallocation has other advantages, for example by allowing the caller to control the "output" type from an algorithm. In the example -above, we could have passed a ``SubArray`` rather than an ``Array``, +above, we could have passed a :class:`SubArray` rather than an :class:`Array`, had we so desired. Taken to its extreme, pre-allocation can make your code uglier, so @@ -530,13 +529,13 @@ Tweaks These are some minor points that might help in tight inner loops. -- Avoid unnecessary arrays. For example, instead of ``sum([x,y,z])`` +- Avoid unnecessary arrays. For example, instead of :func:`sum([x,y,z]) ` use ``x+y+z``. -- Use ``abs2(z)`` instead of ``abs(z)^2`` for complex ``z``. In general, - try to rewrite code to use ``abs2`` instead of ``abs`` for complex arguments. -- Use ``div(x,y)`` for truncating division of integers instead of - ``trunc(x/y)``, ``fld(x,y)`` instead of ``floor(x/y)``, and - ``cld(x,y)`` instead of ``ceil(x/y)``. +- Use :func:`abs2(z) ` instead of :func:`abs(z)^2 ` for complex ``z``. In general, + try to rewrite code to use :func:`abs2` instead of :func:`abs` for complex arguments. +- Use :func:`div(x,y)
` for truncating division of integers instead of + :func:`trunc(x/y) `, :func:`fld(x,y) ` instead of :func:`floor(x/y) `, and + :func:`cld(x,y) ` instead of :func:`ceil(x/y) `. Performance Annotations ----------------------- @@ -544,12 +543,12 @@ Performance Annotations Sometimes you can enable better optimization by promising certain program properties. -- Use ``@inbounds`` to eliminate array bounds checking within expressions. +- Use :obj:`@inbounds` to eliminate array bounds checking within expressions. Be certain before doing this. If the subscripts are ever out of bounds, you may suffer crashes or silent corruption. -- Write ``@simd`` in front of ``for`` loops that are amenable to vectorization. - **This feature is experimental** and could change or disappear in future - versions of Julia. +- Write :obj:`@simd` in front of ``for`` loops that are amenable to vectorization. + **This feature is experimental** and could change or disappear in future + versions of Julia. Here is an example with both forms of markup:: @@ -568,7 +567,7 @@ Here is an example with both forms of markup:: end s end - + function timeit( n, reps ) x = rand(Float32,n) y = rand(Float32,n) @@ -592,33 +591,144 @@ On a computer with a 2.4GHz Intel Core i5 processor, this produces:: The range for a ``@simd for`` loop should be a one-dimensional range. A variable used for accumulating, such as ``s`` in the example, is called -a *reduction variable*. By using``@simd``, you are asserting several +a *reduction variable*. By using :obj:`@simd`, you are asserting several properties of the loop: - It is safe to execute iterations in arbitrary or overlapping order, with special consideration for reduction variables. - Floating-point operations on reduction variables can be reordered, - possibly causing different results than without ``@simd``. + possibly causing different results than without :obj:`@simd`. - No iteration ever waits on another iteration to make forward progress. -A loop containing ``break``, ``continue``, or ``goto`` will cause a +A loop containing ``break``, ``continue``, or :obj:`@goto` will cause a compile-time error. -Using ``@simd`` merely gives the compiler license to vectorize. Whether -it actually does so depends on the compiler. To actually benefit from the -current implementation, your loop should have the following additional +Using :obj:`@simd` merely gives the compiler license to vectorize. Whether +it actually does so depends on the compiler. To actually benefit from the +current implementation, your loop should have the following additional properties: - The loop must be an innermost loop. -- The loop body must be straight-line code. This is why ``@inbounds`` is +- The loop body must be straight-line code. This is why :obj:`@inbounds` is currently needed for all array accesses. The compiler can sometimes turn - short ``&&``, ``||``, and ``?:`` expressions into straight-line code, - if it is safe to evaluate all operands unconditionally. Consider using - ``ifelse`` instead of ``?:`` in the loop if it is safe to do so. -- Accesses must have a stride pattern and cannot be "gathers" (random-index reads) + short ``&&``, ``||``, and ``?:`` expressions into straight-line code, + if it is safe to evaluate all operands unconditionally. Consider using + :func:`ifelse` instead of ``?:`` in the loop if it is safe to do so. +- Accesses must have a stride pattern and cannot be "gathers" (random-index reads) or "scatters" (random-index writes). - The stride should be unit stride. -- In some simple cases, for example with 2-3 arrays accessed in a loop, the - LLVM auto-vectorization may kick in automatically, leading to no further - speedup with ``@simd``. +- In some simple cases, for example with 2-3 arrays accessed in a loop, the + LLVM auto-vectorization may kick in automatically, leading to no further + speedup with :obj:`@simd`. + speedup with ``@simd``. + +.. raw:: html + + +.. _man-code-warntype: + +``@code_warntype`` +------------------ + +The macro ``@code_warntype`` (or its function variant) can sometimes be helpful in diagnosing type-related problems. Here's an example:: + + pos(x) = x < 0 ? 0 : x + + function f(x) + y = pos(x) + sin(y*x+1) + end + julia> @code_warntype f(3.2) + Variables: + x::Float64 + y::UNION(INT64,FLOAT64) + _var0::Float64 + _var3::(Int64,) + _var4::UNION(INT64,FLOAT64) + _var1::Float64 + _var2::Float64 + + Body: + begin # none, line 2: + _var0 = (top(box))(Float64,(top(sitofp))(Float64,0)) + unless (top(box))(Bool,(top(or_int))((top(lt_float))(x::Float64,_var0::Float64)::Bool,(top(box))(Bool,(top(and_int))((top(box))(Bool,(top(and_int))((top(eq_float))(x::Float64,_var0::Float64)::Bool,(top(lt_float))(_var0::Float64,9.223372036854776e18)::Bool)),(top(slt_int))((top(box))(Int64,(top(fptosi))(Int64,_var0::Float64)),0)::Bool)))) goto 1 + _var4 = 0 + goto 2 + 1: + _var4 = x::Float64 + 2: + y = _var4::UNION(INT64,FLOAT64) # line 3: + _var1 = y::UNION(INT64,FLOAT64) * x::Float64::Float64 + _var2 = (top(box))(Float64,(top(add_float))(_var1::Float64,(top(box))(Float64,(top(sitofp))(Float64,1)))) + return (GetfieldNode(Base.Math,:nan_dom_err,Any))((top(ccall))($(Expr(:call1, :(top(tuple)), "sin", GetfieldNode(Base.Math,:libm,Any))),Float64,$(Expr(:call1, :(top(tuple)), :Float64)),_var2::Float64,0)::Float64,_var2::Float64)::Float64 + end::Float64 + +Interpreting the output of ``@code_warntype``, like that of its cousins +``@code_lowered``, ``@code_typed``, ``@code_llvm``, and +``@code_native``, takes a little practice. Your +code is being presented in form that has been partially-digested on +its way to generating compiled machine code. Most of the expressions +are annotated by a type, indicated by the ``::T`` (where ``T`` might +be ``Float64``, for example). The most important characteristic of +``@code_warntype`` is that non-concrete types are displayed in red; in +the above example, such output is shown in all-caps. + +The top part of the output summarizes the type information for the different variables internal to the function. You can see that ``y``, one +of the variables you created, is a ``Union(Int64,Float64)``, due to +the type-instability of ``pos``. There is another variable, +``_var4``, which you can see also has the same type. + +The next lines represent the body of ``f``. The lines starting with a +number followed by a colon (``1:``, ``2:``) are labels, and represent +targets for jumps (via ``goto``) in your code. Looking at the body, +you can see that ``pos`` has been *inlined* into ``f``---everything +before ``2:`` comes from code defined in ``pos``. + +Starting at ``2:``, the variable ``y`` is defined, and again annotated +as a ``Union`` type. Next, we see that the compiler created the +temporary variable ``_var1`` to hold the result of ``y*x``. Because +a ``Float64`` times *either* an ``Int64`` or ``Float64`` yields a ``Float64``, +all type-instability ends here. The net result is that +``f(x::Float64)`` will not be type-unstable in its output, even if +some of the intermediate computations are type-unstable. + +How you use this information is up to you. Obviously, it would be far +and away best to fix ``pos`` to be type-stable: if you did so, all of +the variables in ``f`` would be concrete, and its performance would be +optimal. However, there are circumstances where this kind of +*ephemeral* type instability might not matter too much: for example, +if ``pos`` is never used in isolation, the fact that ``f``\'s output +is type-stable (for ``Float64`` inputs) will shield later code from +the propagating effects of type instability. This is particularly +relevant in cases where fixing the type instability is difficult or +impossible: for example, currently it's not possible to infer the +return type of an anonymous function. In such cases, the tips above +(e.g., adding type annotations and/or breaking up functions) are your +best tools to contain the "damage" from type instability. + +Here is a table which can help you interpret expressions marked as +containing non-leaf types: + +.. |I0| replace:: Interpretation +.. |F0| replace:: Possible fix +.. |I1| replace:: Function with unstable return type +.. |F1| replace:: Make the return value type-stable, even if you have to annotate it +.. |I2| replace:: Call to a type-unstable function +.. |F2| replace:: Fix the function, or annotate the return value +.. |I3| replace:: Accessing elements of poorly-typed arrays +.. |F3| replace:: Use arrays with better-defined types, or annotate the type of individual element accesses +.. |I4| replace:: Getting a field that is of non-leaf type. In this case, ``ArrayContainer`` had a field ``data::Array{T}``. But ``Array`` needs the dimension ``N``, too. +.. |F4| replace:: Use concrete types like ``Array{T,3}`` or ``Array{T,N}``, where ``N`` is now a parameter of ``ArrayContainer`` + ++-------------------------------------------------------------------------+------+------+ +| Marked expression | |I0| | |F0| | ++=========================================================================+======+======+ +| Function ending in ``end::Union(T1,T2)))`` | |I1| | |F1| | ++-------------------------------------------------------------------------+------+------+ +| ``f(x::T)::Union(T1,T2)`` | |I2| | |F2| | ++-------------------------------------------------------------------------+------+------+ +| ``(top(arrayref))(A::Array{Any,1},1)::Any`` | |I3| | |F3| | ++-------------------------------------------------------------------------+------+------+ +| ``(top(getfield))(A::ArrayContainer{Float64},:data)::Array{Float64,N}`` | |I4| | |F4| | ++-------------------------------------------------------------------------+------+------+ diff --git a/doc/manual/running-external-programs.rst b/doc/manual/running-external-programs.rst index 1f1b05b026d1d..f89e40132071f 100644 --- a/doc/manual/running-external-programs.rst +++ b/doc/manual/running-external-programs.rst @@ -1,5 +1,7 @@ .. _man-running-external-programs: +.. currentmodule:: Base + *************************** Running External Programs *************************** @@ -16,12 +18,12 @@ differs in several aspects from the behavior in various shells, Perl, or Ruby: - Instead of immediately running the command, backticks create a - ``Cmd`` object to represent the command. You can use this object to + :obj:`Cmd` object to represent the command. You can use this object to connect the command to others via pipes, run it, and read or write to it. - When the command is run, Julia does not capture its output unless you specifically arrange for it to. Instead, the output of the command by - default goes to ``stdout`` as it would using ``libc``'s ``system`` + default goes to :const:`STDOUT` as it would using ``libc``'s ``system`` call. - The command is never run with a shell. Instead, Julia parses the command syntax directly, appropriately interpolating variables and @@ -34,11 +36,11 @@ Here's a simple example of running an external program:: julia> run(`echo hello`) hello -The ``hello`` is the output of the ``echo`` command, sent to stdout. -The run method itself returns ``nothing``, and throws an ``ErrorException`` +The ``hello`` is the output of the ``echo`` command, sent to :const:`STDOUT`. +The run method itself returns ``nothing``, and throws an :exc:`ErrorException` if the external command fails to run successfully. -If you want to read the output of the external command, the ``readall`` method +If you want to read the output of the external command, :func:`readall` can be used instead:: julia> a=readall(`echo hello`) @@ -47,7 +49,7 @@ can be used instead:: julia> (chomp(a)) == "hello" true -More generally, you can use ``open`` to read from or write to an external +More generally, you can use :func:`open` to read from or write to an external command. For example:: julia> open(`less`, "w", STDOUT) do io @@ -155,7 +157,7 @@ Quoting ------- Inevitably, one wants to write commands that aren't quite so simple, and -it becomes necessary to use quotes. Here's a simple example of a perl +it becomes necessary to use quotes. Here's a simple example of a Perl one-liner at a shell prompt:: sh$ perl -le '$|=1; for (0..3) { print }' @@ -224,8 +226,8 @@ This expression invokes the ``echo`` command with three words as arguments: "hello", "\|", and "sort". The result is that a single line is printed: "hello \| sort". Inside of backticks, a "\|" is just a literal pipe character. How, then, does one construct a pipeline? -Instead of using "\|" inside of backticks, one uses Julia's ``|>`` -operator between ``Cmd`` objects:: +Instead of using "\|" inside of backticks, one uses Julia's :obj:`|>` +operator between :obj:`Cmd` objects:: julia> run(`echo hello` |> `sort`) hello @@ -246,8 +248,8 @@ This prints the highest five user IDs on a UNIX system. The ``cut``, the current ``julia`` process, with no intervening shell process. Julia itself does the work to setup pipes and connect file descriptors that is normally done by the shell. Since Julia does this itself, it retains -better control and can do some things that shells cannot. Note that ``|>`` -only redirects ``stdout``. To redirect ``stderr``, use ``.>`` +better control and can do some things that shells cannot. Note that :obj:`|>` +only redirects :const:`STDOUT`. To redirect :const:`STDERR`, use :obj:`.>`. Julia can run multiple commands in parallel:: @@ -258,7 +260,7 @@ Julia can run multiple commands in parallel:: The order of the output here is non-deterministic because the two ``echo`` processes are started nearly simultaneously, and race to make -the first write to the ``stdout`` descriptor they share with each other +the first write to the :const:`STDOUT` descriptor they share with each other and the ``julia`` parent process. Julia lets you pipe the output from both of these processes to another program:: @@ -297,7 +299,7 @@ prefixing lines with the letter "A", the other with the letter "B". Which consumer gets the first line is non-deterministic, but once that race has been won, the lines are consumed alternately by one process and then the other. (Setting ``$|=1`` in Perl causes each print statement to -flush the ``stdout`` handle, which is necessary for this example to +flush the :const:`STDOUT` handle, which is necessary for this example to work. Otherwise all the output is buffered and printed to the pipe at once, to be read by just one consumer process.) diff --git a/doc/manual/strings.rst b/doc/manual/strings.rst index f0402f81558d0..7766d143e7a69 100644 --- a/doc/manual/strings.rst +++ b/doc/manual/strings.rst @@ -34,15 +34,15 @@ handle non-ASCII data is straightforward. There are a few noteworthy high-level features about Julia's strings: -- ``AbstractString`` is an abstraction, not a concrete type — many different - representations can implement the ``AbstractString`` interface, but they can +- :obj:`AbstractString` is an abstraction, not a concrete type — many different + representations can implement the :obj:`AbstractString` interface, but they can easily be used together and interact transparently. Any string type - can be used in any function expecting a ``AbstractString``. + can be used in any function expecting a :obj:`AbstractString`. - Like C and Java, but unlike most dynamic languages, Julia has a - first-class type representing a single character, called ``Char``. + first-class type representing a single character, called :obj:`Char`. This is just a special kind of 32-bit bitstype whose numeric value represents a Unicode code point. -- As in Java, strings are immutable: the value of a ``AbstractString`` object +- As in Java, strings are immutable: the value of a :obj:`AbstractString` object cannot be changed. To construct a different string value, you construct a new string from parts of other strings. - Conceptually, a string is a *partial function* from indices to @@ -63,10 +63,10 @@ There are a few noteworthy high-level features about Julia's strings: Characters ---------- -A ``Char`` value represents a single character: it is just a 32-bit +A :obj:`Char` value represents a single character: it is just a 32-bit bitstype with a special literal representation and appropriate arithmetic behaviors, whose numeric value is interpreted as a `Unicode code -point `_. Here is how ``Char`` +point `_. Here is how :obj:`Char` values are input and shown: .. doctest:: @@ -77,7 +77,7 @@ values are input and shown: julia> typeof(ans) Char -You can convert a ``Char`` to its integer value, i.e. code point, +You can convert a :obj:`Char` to its integer value, i.e. code point, easily: .. doctest:: @@ -88,8 +88,8 @@ easily: julia> typeof(ans) Int64 -On 32-bit architectures, ``typeof(ans)`` will be ``Int32``. You can -convert an integer value back to a ``Char`` just as easily: +On 32-bit architectures, :func:`typeof(ans) ` will be ``Int32``. You can +convert an integer value back to a :obj:`Char` just as easily: .. doctest:: @@ -164,7 +164,7 @@ also be used: 255 You can do comparisons and a limited amount of arithmetic with -``Char`` values: +:obj:`Char` values: .. doctest:: @@ -183,10 +183,10 @@ You can do comparisons and a limited amount of arithmetic with julia> 'A' + 1 'B' -AbstractString Basics ---------------------- +:obj:`AbstractString` Basics +---------------------------- -AbstractString literals are delimited by double quotes or triple double quotes: +:obj:`AbstractString` literals are delimited by double quotes or triple double quotes: .. doctest:: @@ -215,7 +215,7 @@ element is found at index ``n``, when the string has a length of ``n``. In any indexing expression, the keyword ``end`` can be used as a -shorthand for the last index (computed by ``endof(str)``). +shorthand for the last index (computed by :func:`endof(str) `). You can perform arithmetic and other operations with ``end``, just like a normal value: @@ -262,7 +262,7 @@ Notice that the expressions ``str[k]`` and ``str[k:k]`` do not give the same res julia> str[6:6] "," -The former is a single character value of type ``Char``, while the +The former is a single character value of type :obj:`Char`, while the latter is a string value that happens to contain only a single character. In Julia these are very different things. @@ -314,8 +314,8 @@ In this case, the character ``∀`` is a three-byte character, so the indices 2 and 3 are invalid and the next character's index is 4. Because of variable-length encodings, the number of characters in a -string (given by ``length(s)``) is not always the same as the last index. -If you iterate through the indices 1 through ``endof(s)`` and index +string (given by :func:`length(s) `) is not always the same as the last index. +If you iterate through the indices 1 through :func:`endof(s) ` and index into ``s``, the sequence of characters returned when errors aren't thrown is the sequence of characters comprising the string ``s``. Thus we have the identity that ``length(s) <= endof(s)``, since each @@ -359,10 +359,10 @@ exception handling required: UTF-8 is not the only encoding that Julia supports, and adding support for new encodings is quite easy. In particular, Julia also provides -``UTF16String`` and ``UTF32String`` types, constructed by the -``utf16(s)`` and ``utf32(s)`` functions respectively, for UTF-16 and -UTF-32 encodings. It also provides aliases ``WString`` and -``wstring(s)`` for either UTF-16 or UTF-32 strings, depending on the +:obj:`UTF16String` and :obj:`UTF32String` types, constructed by +:func:`utf16` and :func:`utf32` respectively, for UTF-16 and +UTF-32 encodings. It also provides aliases :obj:`WString` and +:func:`wstring` for either UTF-16 or UTF-32 strings, depending on the size of ``Cwchar_t``. Additional discussion of other encodings and how to implement support for them is beyond the scope of this document for the time being. For further discussion of UTF-8 encoding issues, see @@ -409,9 +409,9 @@ can interpolate any expression into a string using parentheses: julia> "1 + 2 = $(1 + 2)" "1 + 2 = 3" -Both concatenation and string interpolation call the generic -``string`` function to convert objects into string form. Most -non-``AbstractString`` objects are converted to strings closely +Both concatenation and string interpolation call +:func:`string` to convert objects into string form. Most +non-:obj:`AbstractString` objects are converted to strings closely corresponding to how they are entered as literal expressions: .. doctest:: @@ -425,7 +425,7 @@ corresponding to how they are entered as literal expressions: julia> "v: $v" "v: [1,2,3]" -The ``string`` function is the identity for ``AbstractString`` and ``Char`` +:func:`string` is the identity for :obj:`AbstractString` and :obj:`Char` values, so these are interpolated into strings as themselves, unquoted and unescaped: @@ -493,6 +493,27 @@ a third argument: julia> search("xylophone", 'o', 8) 0 +You can use the :func:`contains` function to check if a substring is +contained in a string: + +.. doctest:: + + julia> contains("Hello, world.", "world") + true + + julia> contains("Xylophon", "o") + true + + julia> contains("Xylophon", "a") + false + + julia> contains("Xylophon", 'o') + ERROR: `contains` has no method matching contains(::ASCIIString, ::Char) + +The last error is because ``'o'`` is a character literal, and :func:`contains` +is a generic function that looks for subsequences. To look for an element in a +sequence, you must use :func:`in` instead. + Two other handy string functions are :func:`repeat` and :func:`join`: .. doctest:: @@ -505,18 +526,18 @@ Two other handy string functions are :func:`repeat` and :func:`join`: Some other useful functions include: -- ``endof(str)`` gives the maximal (byte) index that can be used to +- :func:`endof(str) ` gives the maximal (byte) index that can be used to index into ``str``. -- ``length(str)`` the number of characters in ``str``. -- ``i = start(str)`` gives the first valid index at which a character +- :func:`length(str) ` the number of characters in ``str``. +- :func:`i = start(str) ` gives the first valid index at which a character can be found in ``str`` (typically 1). -- ``c, j = next(str,i)`` returns next character at or after the index +- :func:`c, j = next(str,i) ` returns next character at or after the index ``i`` and the next valid character index following that. With - ``start`` and ``endof``, can be used to iterate through the + :func:`start` and :func:`endof`, can be used to iterate through the characters in ``str``. -- ``ind2chr(str,i)`` gives the number of characters in ``str`` up to +- :func:`ind2chr(str,i) ` gives the number of characters in ``str`` up to and including any at index ``i``. -- ``chr2ind(str,j)`` gives the index at which the ``j``\ th character +- :func:`chr2ind(str,j) ` gives the index at which the ``j``\ th character in ``str`` occurs. .. _man-non-standard-string-literals: @@ -558,7 +579,7 @@ any options turned on just uses ``r"..."``: julia> typeof(ans) Regex (constructor with 3 methods) -To check if a regex matches a string, use the :func:`ismatch` function: +To check if a regex matches a string, use :func:`ismatch`: .. doctest:: @@ -568,7 +589,7 @@ To check if a regex matches a string, use the :func:`ismatch` function: julia> ismatch(r"^\s*(?:#|$)", "# a comment") true -As one can see here, ``ismatch`` simply returns true or false, +As one can see here, :func:`ismatch` simply returns true or false, indicating whether the given regex matches the string or not. Commonly, however, one wants to know not just whether a string matched, but also *how* it matched. To capture this information about a match, use the @@ -581,7 +602,7 @@ however, one wants to know not just whether a string matched, but also julia> match(r"^\s*(?:#|$)", "# a comment") RegexMatch("#") -If the regular expression does not match the given string, ``match`` +If the regular expression does not match the given string, :func:`match` returns ``nothing`` — a special value that does not print anything at the interactive prompt. Other than not printing, it is a completely normal value and you can test for it programmatically:: @@ -593,8 +614,8 @@ normal value and you can test for it programmatically:: println("blank or comment") end -If a regular expression does match, the value returned by ``match`` is a -``RegexMatch`` object. These objects record how the expression matches, +If a regular expression does match, the value returned by :func:`match` is a +:obj:`RegexMatch` object. These objects record how the expression matches, including the substring that the pattern matches and any captured substrings, if there are any. This example only captures the portion of the substring that matches, but perhaps we want to capture any non-blank @@ -605,7 +626,7 @@ text after the comment character. We could do the following: julia> m = match(r"^\s*(?:#\s*(.*?)\s*$|$)", "# a comment ") RegexMatch("# a comment ", 1="a comment") -When calling ``match``, you have the option to specify an index at +When calling :func:`match`, you have the option to specify an index at which to start the search. For example: .. doctest:: @@ -619,7 +640,7 @@ which to start the search. For example: julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",11) RegexMatch("3") -You can extract the following info from a ``RegexMatch`` object: +You can extract the following info from a :obj:`RegexMatch` object: - the entire substring matched: ``m.match`` - the captured substrings as a tuple of strings: ``m.captures`` @@ -820,7 +841,7 @@ Version Number Literals ----------------------- Version numbers can easily be expressed with non-standard string literals of -the form ``v"..."``. Version number literals create ``VersionNumber`` objects +the form ``v"..."``. Version number literals create :obj:`VersionNumber` objects which follow the specifications of `semantic versioning `_, and therefore are composed of major, minor and patch numeric values, followed by pre-release and build alpha-numeric annotations. For example, @@ -831,10 +852,10 @@ therefore e.g. ``v"0.2"`` is equivalent to ``v"0.2.0"`` (with empty pre-release/build annotations), ``v"2"`` is equivalent to ``v"2.0.0"``, and so on. -``VersionNumber`` objects are mostly useful to easily and correctly compare two +:obj:`VersionNumber` objects are mostly useful to easily and correctly compare two (or more) versions. For example, the constant ``VERSION`` holds Julia version -number as a ``VersionNumber`` object, and therefore one can define some -version-specific behaviour using simple statements as:: +number as a :obj:`VersionNumber` object, and therefore one can define some +version-specific behavior using simple statements as:: if v"0.2" <= VERSION < v"0.3-" # do something specific to 0.2 release series @@ -860,6 +881,6 @@ the trailing ``-`` should always be used on upper bounds unless there's a good reason not to), but they must not be used as the actual version number of anything, as they are invalid in the semantic versioning scheme. -Besides being used for the ``VERSION`` constant, ``VersionNumber`` objects are -widely used in the ``Pkg`` module, to specify packages versions and their +Besides being used for the :const:`VERSION` constant, :obj:`VersionNumber` objects are +widely used in the :mod:`Pkg ` module, to specify packages versions and their dependencies. diff --git a/doc/manual/style-guide.rst b/doc/manual/style-guide.rst index b67f2d45716c7..8b26f9c56d14c 100644 --- a/doc/manual/style-guide.rst +++ b/doc/manual/style-guide.rst @@ -1,5 +1,7 @@ .. _man-style-guide: +.. currentmodule:: Base + ************* Style Guide ************* @@ -19,7 +21,7 @@ Furthermore, code inside functions tends to run much faster than top level code, due to how Julia's compiler works. It is also worth emphasizing that functions should take arguments, instead -of operating directly on global variables (aside from constants like ``pi``). +of operating directly on global variables (aside from constants like :const:`pi`). Avoid writing overly-specific types ----------------------------------- @@ -40,7 +42,7 @@ example, don't declare an argument to be of type ``Int`` or ``Int32`` if it really could be any integer, expressed with the abstract type ``Integer``. In fact, in many cases you can omit the argument type altogether, unless it is needed to disambiguate from other method -definitions, since a ``MethodError`` will be thrown anyway if a type +definitions, since a :exc:`MethodError` will be thrown anyway if a type is passed that does not support any of the requisite operations. (This is known as `duck typing `_.) @@ -52,15 +54,15 @@ For example, consider the following definitions of a function addone(x::Number) = x + one(x) # any numeric type addone(x) = x + one(x) # any type supporting + and one -The last definition of ``addone`` handles any type supporting the -``one`` function (which returns 1 in the same type as ``x``, which -avoids unwanted type promotion) and the ``+`` function with those +The last definition of ``addone`` handles any type supporting +:func:`one` (which returns 1 in the same type as ``x``, which +avoids unwanted type promotion) and the :obj:`+` function with those arguments. The key thing to realize is that there is *no performance penalty* to defining *only* the general ``addone(x) = x + one(x)``, because Julia will automatically compile specialized versions as needed. For example, the first time you call ``addone(12)``, Julia will automatically compile a specialized ``addone`` function for -``x::Int`` arguments, with the call to ``one`` replaced by its inlined +``x::Int`` arguments, with the call to :func:`one` replaced by its inlined value ``1``. Therefore, the first three definitions of ``addone`` above are completely redundant. @@ -109,8 +111,8 @@ use:: The Julia standard library uses this convention throughout and contains examples of functions with both copying and modifying forms -(e.g., ``sort`` and ``sort!``), and others which are just modifying -(e.g., ``push!``, ``pop!``, ``splice!``). It is typical for +(e.g., :func:`sort` and :func:`sort!`), and others which are just modifying +(e.g., :func:`push!`, :func:`pop!`, :func:`splice!`). It is typical for such functions to also return the modified array for convenience. Avoid strange type Unions @@ -139,7 +141,7 @@ It is usually not much help to construct arrays like the following:: a = Array(Union(Int,AbstractString,Tuple,Array), n) -In this case ``cell(n)`` is better. It is also more helpful to the compiler +In this case :func:`cell(n) ` is better. It is also more helpful to the compiler to annotate specific uses (e.g. ``a[i]::Int``) than to try to pack many alternatives into one type. @@ -148,14 +150,14 @@ Use naming conventions consistent with Julia's ``base/`` - modules and type names use capitalization and camel case: ``module SparseMatrix``, ``immutable UnitRange``. -- functions are lowercase (``maximum``, ``convert``) and, - when readable, with multiple words squashed together (``isequal``, ``haskey``). +- functions are lowercase (:func:`maximum`, :func:`convert`) and, + when readable, with multiple words squashed together (:func:`isequal`, :func:`haskey`). When necessary, use underscores as word separators. Underscores are also used to indicate a combination of - concepts (``remotecall_fetch`` as a more efficient implementation - of ``remotecall(fetch(...))``) or as modifiers (``sum_kbn``). + concepts (:func:`remotecall_fetch` as a more efficient implementation + of ``remotecall(fetch(...))``) or as modifiers (:func:`sum_kbn`). - conciseness is valued, but avoid abbreviation - (``indexin`` rather than ``indxin``) as it becomes difficult to + (:func:`indexin` rather than ``indxin()``) as it becomes difficult to remember whether and how particular words are abbreviated. If a function name requires multiple words, consider whether it might @@ -183,7 +185,7 @@ Don't overuse ... Splicing function arguments can be addictive. Instead of ``[a..., b...]``, use simply ``[a, b]``, which already concatenates arrays. -``collect(a)`` is better than ``[a...]``, but since ``a`` is already iterable +:func:`collect(a) ` is better than ``[a...]``, but since ``a`` is already iterable it is often even better to leave it alone, and not convert it to an array. Don't use unnecessary static parameters @@ -198,7 +200,7 @@ should be written as:: foo(x::Real) = ... instead, especially if ``T`` is not used in the function body. -Even if ``T`` is used, it can be replaced with ``typeof(x)`` if convenient. +Even if ``T`` is used, it can be replaced with :func:`typeof(x) ` if convenient. There is no performance difference. Note that this is not a general caution against static parameters, just against uses where they are not needed. @@ -233,7 +235,7 @@ Don't overuse macros Be aware of when a macro could really be a function instead. -Calling ``eval`` inside a macro is a particularly dangerous warning sign; +Calling :func:`eval` inside a macro is a particularly dangerous warning sign; it means the macro will only work when called at the top level. If such a macro is written as a function instead, it will naturally have access to the run-time values it needs. @@ -267,13 +269,13 @@ It is possible to write definitions like the following:: This would provide custom showing of vectors with a specific new element type. While tempting, this should be avoided. The trouble is that users will expect -a well-known type like ``Vector`` to behave in a certain way, and overly +a well-known type like :func:`Vector` to behave in a certain way, and overly customizing its behavior can make it harder to work with. Be careful with type equality ----------------------------- -You generally want to use ``isa`` and ``<:`` (``issubtype``) for testing types, +You generally want to use :func:`isa` and ``<:`` (:func:`issubtype`) for testing types, not ``==``. Checking types for exact equality typically only makes sense when comparing to a known concrete type (e.g. ``T == Float64``), or if you *really, really* know what you're doing. @@ -285,4 +287,5 @@ Since higher-order functions are often called with anonymous functions, it is easy to conclude that this is desirable or even necessary. But any function can be passed directly, without being "wrapped" in an anonymous function. Instead of writing ``map(x->f(x), a)``, write -``map(f, a)``. +:func:`map(f, a) `. + diff --git a/doc/manual/types.rst b/doc/manual/types.rst index 8cb4023227567..92d459ab8b57a 100644 --- a/doc/manual/types.rst +++ b/doc/manual/types.rst @@ -1,5 +1,7 @@ .. _man-types: +.. currentmodule:: Base + ********* Types ********* @@ -62,7 +64,7 @@ Julia's type system that should be mentioned up front are: bound to values. - Both abstract and concrete types can be parameterized by other types. They can also be parameterized by symbols, by values of any type for - which `isbits` returns true (essentially, things like numbers and bools + which :func:`isbits` returns true (essentially, things like numbers and bools that are stored like C types or structs with no pointers to other objects), and also by tuples thereof. Type parameters may be omitted when they do not need to be referenced or restricted. @@ -115,7 +117,7 @@ operator means something a bit different: it declares the variable to always have the specified type, like a type declaration in a statically-typed language such as C. Every value assigned to the variable will be converted to the declared type -using the ``convert`` function: +using :func:`convert`: .. doctest:: foo-func @@ -162,14 +164,14 @@ the type system: they form the conceptual hierarchy which makes Julia's type system more than just a collection of object implementations. Recall that in :ref:`man-integers-and-floating-point-numbers`, we -introduced a variety of concrete types of numeric values: ``Int8``, -``UInt8``, ``Int16``, ``UInt16``, ``Int32``, ``UInt32``, ``Int64``, -``UInt64``, ``Int128``, ``UInt128``, ``Float16``, ``Float32``, and -``Float64``. Although they have different representation sizes, ``Int8``, -``Int16``, ``Int32``, ``Int64`` and ``Int128`` all have in common that -they are signed integer types. Likewise ``UInt8``, ``UInt16``, ``UInt32``, -``UInt64`` and ``UInt128`` are all unsigned integer types, while -``Float16``, ``Float32`` and ``Float64`` are distinct in being +introduced a variety of concrete types of numeric values: :class:`Int8`, +:class:`UInt8`, :class:`Int16`, :class:`UInt16`, :class:`Int32`, :class:`UInt32`, :class:`Int64`, +:class:`UInt64`, :class:`Int128`, :class:`UInt128`, :class:`Float16`, :class:`Float32`, and +:class:`Float64`. Although they have different representation sizes, :class:`Int8`, +:class:`Int16`, :class:`Int32`, :class:`Int64` and :class:`Int128` all have in common that +they are signed integer types. Likewise :class:`UInt8`, :class:`UInt16`, :class:`UInt32`, +:class:`UInt64` and :class:`UInt128` are all unsigned integer types, while +:class:`Float16`, :class:`Float32` and :class:`Float64` are distinct in being floating-point types rather than integers. It is common for a piece of code to make sense, for example, only if its arguments are some kind of integer, but not really depend on what particular *kind* of integer. For example, @@ -191,12 +193,12 @@ given by ``«name»``. This name can be optionally followed by ``<:`` and an already-existing type, indicating that the newly declared abstract type is a subtype of this "parent" type. -When no supertype is given, the default supertype is ``Any`` — a +When no supertype is given, the default supertype is :obj:`Any` — a predefined abstract type that all objects are instances of and all types -are subtypes of. In type theory, ``Any`` is commonly called "top" +are subtypes of. In type theory, :obj:`Any` is commonly called "top" because it is at the apex of the type graph. Julia also has a predefined abstract "bottom" type, at the nadir of the type graph, which is called -``None``. It is the exact opposite of ``Any``: no object is an instance +``None``. It is the exact opposite of :obj:`Any`: no object is an instance of ``None`` and all types are supertypes of ``None``. Let's consider some of the abstract types that make up Julia's numerical @@ -209,15 +211,15 @@ hierarchy:: abstract Signed <: Integer abstract Unsigned <: Integer -The ``Number`` type is a direct child type of ``Any``, and ``Real`` is -its child. In turn, ``Real`` has two children (it has more, but only two -are shown here; we'll get to the others later): ``Integer`` and -``FloatingPoint``, separating the world into representations of integers and +The :obj:`Number` type is a direct child type of :obj:`Any`, and :obj:`Real` is +its child. In turn, :obj:`Real` has two children (it has more, but only two +are shown here; we'll get to the others later): :class:`Integer` and +:class:`FloatingPoint`, separating the world into representations of integers and representations of real numbers. Representations of real numbers include, of course, floating-point types, but also include other types, -such as rationals. Hence, ``FloatingPoint`` is a proper subtype of -``Real``, including only floating-point representations of real numbers. -Integers are further subdivided into ``Signed`` and ``Unsigned`` +such as rationals. Hence, :class:`FloatingPoint` is a proper subtype of +:obj:`Real`, including only floating-point representations of real numbers. +Integers are further subdivided into :obj:`Signed` and :obj:`Unsigned` varieties. The ``<:`` operator in general means "is a subtype of", and, used in @@ -248,18 +250,18 @@ to ``x::Any`` and ``y::Any``. When this function is invoked, say as information on multiple dispatch.) Assuming no method more specific than the above is found, Julia next internally -defines and compiles a method called ``myplus`` specifically for two ``Int`` +defines and compiles a method called ``myplus`` specifically for two :class:`Int` arguments based on the generic function given above, i.e., it implicitly defines and compiles:: - + function myplus(x::Int,y::Int) x+y end - + and finally, it invokes this specific method. Thus, abstract types allow programmers to write generic functions that can -later be used as the default method by many combinations of concrete types. +later be used as the default method by many combinations of concrete types. Thanks to multiple dispatch, the programmer has full control over whether the default or more specific method is used. @@ -305,25 +307,25 @@ The general syntaxes for declaration of a ``bitstype`` are:: The number of bits indicates how much storage the type requires and the name gives the new type a name. A bits type can optionally be declared to be a subtype of some supertype. If a supertype is omitted, then the -type defaults to having ``Any`` as its immediate supertype. The -declaration of ``Bool`` above therefore means that a boolean value takes -eight bits to store, and has ``Integer`` as its immediate supertype. +type defaults to having :obj:`Any` as its immediate supertype. The +declaration of :obj:`Bool` above therefore means that a boolean value takes +eight bits to store, and has :class:`Integer` as its immediate supertype. Currently, only sizes that are multiples of 8 bits are supported. Therefore, boolean values, although they really need just a single bit, cannot be declared to be any smaller than eight bits. -The types ``Bool``, ``Int8`` and ``UInt8`` all have identical +The types :obj:`Bool`, :class:`Int8` and :class:`UInt8` all have identical representations: they are eight-bit chunks of memory. Since Julia's type system is nominative, however, they are not interchangeable despite having identical structure. Another fundamental difference between them -is that they have different supertypes: ``Bool``'s direct supertype is -``Integer``, ``Int8``'s is ``Signed``, and ``UInt8``'s is ``Unsigned``. -All other differences between ``Bool``, ``Int8``, and ``UInt8`` are +is that they have different supertypes: :obj:`Bool`'s direct supertype is +:class:`Integer`, :class:`Int8`'s is :obj:`Signed`, and :class:`UInt8`'s is :obj:`Unsigned`. +All other differences between :obj:`Bool`, :class:`Int8`, and :class:`UInt8` are matters of behavior — the way functions are defined to act when given objects of these types as arguments. This is why a nominative type system is necessary: if structure determined type, which in turn -dictates behavior, then it would be impossible to make ``Bool`` behave any -differently than ``Int8`` or ``UInt8``. +dictates behavior, then it would be impossible to make :obj:`Bool` behave any +differently than :class:`Int8` or :class:`UInt8`. .. _man-composite-types: @@ -331,7 +333,7 @@ Composite Types --------------- `Composite types `_ -are called records, structures (``structs`` in C), or objects in various +are called records, structures (``struct``\ s in C), or objects in various languages. A composite type is a collection of named fields, an instance of which can be treated as a single value. In many languages, composite types are the only kind of user-definable type, and they are by far the @@ -370,7 +372,7 @@ operator: qux::Float64 end -Fields with no type annotation default to ``Any``, and can accordingly +Fields with no type annotation default to :obj:`Any`, and can accordingly hold any type of value. New objects of composite type ``Foo`` are created by applying the @@ -386,14 +388,14 @@ New objects of composite type ``Foo`` are created by applying the When a type is applied like a function it is called a *constructor*. Two constructors are generated automatically (these are called *default -constructors*). One accepts any arguments and calls ``convert`` to convert +constructors*). One accepts any arguments and calls :func:`convert` to convert them to the types of the fields, and the other accepts arguments that match the field types exactly. The reason both of these are generated is that this makes it easier to add new definitions without inadvertently replacing a default constructor. Since the ``bar`` field is unconstrained in type, any value will do. -However, the value for ``baz`` must be convertible to ``Int``: +However, the value for ``baz`` must be convertible to :class:`Int`: .. doctest:: @@ -410,7 +412,7 @@ You may find a list of field names using the ``names`` function. :bar :baz :qux - + You can access the field values of a composite object using the traditional ``foo.bar`` notation: @@ -508,7 +510,7 @@ i.e., if the fields of objects passed around by copying could be modified, then it would become more difficult to reason about certain instances of generic code. For example, suppose ``x`` is a function argument of an abstract type, and suppose that the function changes a field: ``x.isprocessed = true``. Depending on whether ``x`` is passed by copying -or by reference, this statement may or may not alter the actual argument in the +or by reference, this statement may or may not alter the actual argument in the calling routine. Julia sidesteps the possibility of creating functions with unknown effects in this scenario by forbidding modification of fields @@ -527,7 +529,7 @@ are actually all closely related. They share the same key properties: - They may have parameters. Because of these shared properties, these types are internally -represented as instances of the same concept, ``DataType``, which +represented as instances of the same concept, :obj:`DataType`, which is the type of any of these types: .. doctest:: @@ -538,14 +540,14 @@ is the type of any of these types: julia> typeof(Int) DataType -A ``DataType`` may be abstract or concrete. If it is concrete, it +A :obj:`DataType` may be abstract or concrete. If it is concrete, it has a specified size, storage layout, and (optionally) field names. -Thus a bits type is a ``DataType`` with nonzero size, but no field -names. A composite type is a ``DataType`` that has field names or +Thus a bits type is a :obj:`DataType` with nonzero size, but no field +names. A composite type is a :obj:`DataType` that has field names or is empty (zero size). Every concrete value in the system is either an instance of some -``DataType``, or is a tuple. +:obj:`DataType`, or is a tuple. Tuple Types ----------- @@ -663,7 +665,7 @@ all type decisions at compile time, many traditional difficulties encountered in static parametric type systems can be relatively easily handled. -All declared types (the ``DataType`` variety) can be parameterized, with +All declared types (the :obj:`DataType` variety) can be parameterized, with the same syntax in each case. We will discuss them in the following order: first, parametric composite types, then parametric abstract types, and finally parametric bits types. @@ -693,7 +695,7 @@ that's precisely the point of parametric types: it can be any type at all (or an integer, actually, although here it's clearly used as a type). ``Point{Float64}`` is a concrete type equivalent to the type defined by replacing ``T`` in the definition of ``Point`` with -``Float64``. Thus, this single declaration actually declares an +:class:`Float64`. Thus, this single declaration actually declares an unlimited number of types: ``Point{Float64}``, ``Point{AbstractString}``, ``Point{Int64}``, etc. Each of these is now a usable concrete type: @@ -763,20 +765,20 @@ types have different representations in memory: - An instance of ``Point{Float64}`` can be represented compactly and efficiently as an immediate pair of 64-bit values; - An instance of ``Point{Real}`` must be able to hold any pair of - instances of ``Real``. Since objects that are instances of ``Real`` + instances of :obj:`Real`. Since objects that are instances of :obj:`Real` can be of arbitrary size and structure, in practice an instance of ``Point{Real}`` must be represented as a pair of pointers to - individually allocated ``Real`` objects. + individually allocated :obj:`Real` objects. The efficiency gained by being able to store ``Point{Float64}`` objects with immediate values is magnified enormously in the case of arrays: an ``Array{Float64}`` can be stored as a contiguous memory block of 64-bit floating-point values, whereas an ``Array{Real}`` must be an array of -pointers to individually allocated ``Real`` objects — which may well be +pointers to individually allocated :obj:`Real` objects — which may well be `boxed `_ 64-bit floating-point values, but also might be arbitrarily large, complex objects, which are declared to be implementations of the -``Real`` abstract type. +:obj:`Real` abstract type. How does one construct a ``Point`` object? It is possible to define custom constructors for composite types, which will be discussed in @@ -787,7 +789,7 @@ given and the other in which they are implied by the arguments to the object constructor. Since the type ``Point{Float64}`` is a concrete type equivalent to -``Point`` declared with ``Float64`` in place of ``T``, it can be applied +``Point`` declared with :class:`Float64` in place of ``T``, it can be applied as a constructor accordingly: .. doctest:: @@ -932,8 +934,8 @@ constrain the range of ``T`` like so:: abstract Pointy{T<:Real} With such a declaration, it is acceptable to use any type that is a -subtype of ``Real`` in place of ``T``, but not types that are not -subtypes of ``Real``: +subtype of :obj:`Real` in place of ``T``, but not types that are not +subtypes of :obj:`Real`: .. testsetup:: real-pointy @@ -963,7 +965,7 @@ same manner:: To give a real-world example of how all this parametric type machinery can be useful, here is the actual definition of Julia's -``Rational`` immutable type (except that we omit the constructor here +:obj:`Rational` immutable type (except that we omit the constructor here for simplicity), representing an exact ratio of integers:: immutable Rational{T<:Integer} <: Real @@ -972,9 +974,9 @@ for simplicity), representing an exact ratio of integers:: end It only makes sense to take ratios of integer values, so the parameter -type ``T`` is restricted to being a subtype of ``Integer``, and a ratio +type ``T`` is restricted to being a subtype of :class:`Integer`, and a ratio of integers represents a value on the real number line, so any -``Rational`` is an instance of the ``Real`` abstraction. +:obj:`Rational` is an instance of the :obj:`Real` abstraction. .. _man-singleton-types: @@ -1001,9 +1003,9 @@ at some examples: julia> isa(Float64, Type{Real}) false -In other words, ``isa(A,Type{B})`` is true if and only if ``A`` and +In other words, :func:`isa(A,Type{B}) ` is true if and only if ``A`` and ``B`` are the same object and that object is a type. Without the -parameter, ``Type`` is simply an abstract type which has all type +parameter, :obj:`Type` is simply an abstract type which has all type objects as its instances, including, of course, singleton types: .. doctest:: @@ -1077,8 +1079,8 @@ Type Aliases Sometimes it is convenient to introduce a new name for an already expressible type. For such occasions, Julia provides the ``typealias`` -mechanism. For example, ``UInt`` is type aliased to either ``UInt32`` or -``UInt64`` as is appropriate for the size of pointers on the system:: +mechanism. For example, :class:`UInt` is type aliased to either :class:`UInt32` or +:class:`UInt64` as is appropriate for the size of pointers on the system:: # 32-bit system: julia> UInt @@ -1096,8 +1098,8 @@ This is accomplished via the following code in ``base/boot.jl``:: typealias UInt UInt32 end -Of course, this depends on what ``Int`` is aliased to — but that is -predefined to be the correct type — either ``Int32`` or ``Int64``. +Of course, this depends on what :class:`Int` is aliased to — but that is +predefined to be the correct type — either :class:`Int32` or :class:`Int64`. For parametric types, ``typealias`` can be convenient for providing names for cases where some of the parameter choices are fixed. @@ -1133,7 +1135,7 @@ This declaration of ``Vector`` creates a subtype relation ``typealias`` statement creates such a relation; for example, the statement:: typealias AA{T} Array{Array{T,1},1} - + does not create the relation ``AA{Int} <: AA``. The reason is that ``Array{Array{T,1},1}`` is not an abstract type at all; in fact, it is a concrete type describing a 1-dimensional array in which each entry @@ -1159,7 +1161,7 @@ true or false: julia> isa(1,FloatingPoint) false -The ``typeof`` function, already used throughout the manual in examples, +The :func:`typeof` function, already used throughout the manual in examples, returns the type of its argument. Since, as noted above, types are objects, they also have types, and we can ask what their types are: @@ -1176,7 +1178,7 @@ objects, they also have types, and we can ask what their types are: What if we repeat the process? What is the type of a type of a type? As it happens, types are all composite values and thus all have a type of -``DataType``: +:obj:`DataType`: .. doctest:: @@ -1186,10 +1188,10 @@ As it happens, types are all composite values and thus all have a type of julia> typeof(UnionType) DataType -The reader may note that ``DataType`` shares with the empty tuple +The reader may note that :obj:`DataType` shares with the empty tuple (see `above <#tuple-types>`_), the distinction of being its own type -(i.e. a fixed point of the ``typeof`` function). This leaves any number -of tuple types recursively built with ``()`` and ``DataType`` as +(i.e. a fixed point of the :func:`typeof` function). This leaves any number +of tuple types recursively built with ``()`` and :obj:`DataType` as their only atomic values, which are their own type: .. doctest:: @@ -1209,11 +1211,11 @@ their only atomic values, which are their own type: julia> typeof(((),DataType)) ((),DataType) -All fixed points of the ``typeof`` function are like this. +All fixed points of :func:`typeof` are like this. -Another operation that applies to some types is ``super``, which +Another operation that applies to some types is :func:`super`, which reveals a type's supertype. -Only declared types (``DataType``) have unambiguous supertypes: +Only declared types (:obj:`DataType`) have unambiguous supertypes: .. doctest:: @@ -1229,8 +1231,8 @@ Only declared types (``DataType``) have unambiguous supertypes: julia> super(Any) Any -If you apply ``super`` to other type objects (or non-type objects), a -"no method" error is raised:: +If you apply :func:`super` to other type objects (or non-type objects), a +:exc:`MethodError` is raised:: julia> super(Union(Float64,Int64)) ERROR: `super` has no method matching super(::Type{Union(Float64,Int64)}) @@ -1251,15 +1253,15 @@ type that can contain either zero or one values. ``Nullable{T}`` provides a minimal interface designed to ensure that interactions with missing values are safe. At present, the interface consists of four possible interactions: -- Construct a ``Nullable`` object. -- Check if an ``Nullable`` object has a missing value. -- Access the value of a ``Nullable`` object with a guarantee that a - ``NullException`` will be thrown if the object's value is missing. -- Access the value of a ``Nullable`` object with a guarantee that a default +- Construct a :obj:`Nullable` object. +- Check if an :obj:`Nullable` object has a missing value. +- Access the value of a :obj:`Nullable` object with a guarantee that a + :exc:`NullException` will be thrown if the object's value is missing. +- Access the value of a :obj:`Nullable` object with a guarantee that a default value of type ``T`` will be returned if the object's value is missing. -Constructing ``Nullable`` objects -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Constructing :obj:`Nullable` objects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To construct an object representing a missing value of type ``T``, use the ``Nullable{T}()`` function: @@ -1284,15 +1286,14 @@ To construct an object representing a non-missing value of type ``T``, use the julia> x3 = Nullable([1, 2, 3]) Nullable([1, 2, 3]) -Note the core distinction between these two ways of constructing a ``Nullable`` +Note the core distinction between these two ways of constructing a :obj:`Nullable` object: in one style, you provide a type, ``T``, as a function parameter; in the other style, you provide a single value of type ``T`` as an argument. -Checking if an ``Nullable`` object has a value -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Checking if an :obj:`Nullable` object has a value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can check if a ``Nullable`` object has any value using the ``isnull`` -function: +You can check if a :obj:`Nullable` object has any value using :func:`isnull`: .. doctest:: @@ -1302,11 +1303,10 @@ function: julia> isnull(Nullable(0.0)) false -Safely accessing the value of an ``Nullable`` object -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Safely accessing the value of an :obj:`Nullable` object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can safely access the value of an ``Nullable`` object using the ``get`` -function: +You can safely access the value of an :obj:`Nullable` object using :func:`get`: .. doctest:: @@ -1318,13 +1318,13 @@ function: 1.0 If the value is not present, as it would be for ``Nullable{Float64}``, a -``NullException`` error will be thrown. The error-throwing nature of the -``get`` function ensures that any attempt to access a missing value immediately +:exc:`NullException` error will be thrown. The error-throwing nature of the +:func:`get` function ensures that any attempt to access a missing value immediately fails. In cases for which a reasonable default value exists that could be used -when a ``Nullable`` object's value turns out to be missing, you can provide this -default value as a second argument to ``get``: +when a :obj:`Nullable` object's value turns out to be missing, you can provide this +default value as a second argument to :func:`get`: .. doctest:: @@ -1335,8 +1335,8 @@ default value as a second argument to ``get``: 1.0 Note that this default value will automatically be converted to the type of -the ``Nullable`` object that you attempt to access using the ``get`` function. +the :obj:`Nullable` object that you attempt to access using the :func:`get` function. For example, in the code shown above the value ``0`` would be automatically -converted to a ``Float64`` value before being returned. The presence of default -replacement values makes it easy to use the ``get`` function to write +converted to a :class:`Float64` value before being returned. The presence of default +replacement values makes it easy to use the :func:`get` function to write type-stable code that interacts with sources of potentially missing values. diff --git a/doc/manual/variables-and-scoping.rst b/doc/manual/variables-and-scoping.rst index 4c4267d631292..2790150ff19c1 100644 --- a/doc/manual/variables-and-scoping.rst +++ b/doc/manual/variables-and-scoping.rst @@ -1,5 +1,7 @@ .. _man-variables-and-scoping: +.. currentmodule:: Base + ******************** Scope of Variables ******************** @@ -28,7 +30,7 @@ The constructs introducing such blocks are: - ``type`` blocks. Notably missing from this list are -:ref:`begin blocks `, which do +:ref:`begin blocks ` and :ref:`if blocks `, which do *not* introduce new scope blocks. Certain constructs introduce new variables into the current innermost @@ -170,9 +172,9 @@ even or odd:: julia> odd(3) true -Julia provides built-in, efficient functions to test this called -``iseven`` and ``isodd`` so the above definitions should only be taken -as examples. +Julia provides built-in, efficient functions to test for oddness and evenness +called :func:`iseven` and :func:`isodd` so the above definitions should only be +taken as examples. Since functions can be used before they are defined, as long as they are defined by the time they are actually called, no syntax for forward diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 7d8bcbe8262bb..ab75aefe0b34b 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -1422,8 +1422,8 @@ Strings Returns an iterator over substrings of ``s`` that correspond to the extended graphemes in the string, as defined by Unicode UAX #29. (Roughly, these are what users would perceive as single characters, - even though they may contain more than one codepoint; for example - a letter combined with an accent mark is a single grapheme.) + even though they may contain more than one codepoint; for example + a letter combined with an accent mark is a single grapheme.) .. function:: is_valid_ascii(s) -> Bool @@ -2335,15 +2335,20 @@ Text I/O Equivalent to ``writedlm`` with ``delim`` set to comma. -.. function:: Base64Pipe(ostream) +.. function:: Base64EncodePipe(ostream) Returns a new write-only I/O stream, which converts any bytes written to it into base64-encoded ASCII bytes written to ``ostream``. Calling ``close`` on the ``Base64Pipe`` stream is necessary to complete the encoding (but does not close ``ostream``). -.. function:: base64(writefunc, args...) - base64(args...) +.. function:: Base64DecodePipe(istream) + + Returns a new read-only I/O stream, which decodes base64-encoded data + read from ``istream``. + +.. function:: base64encode(writefunc, args...) + base64encode(args...) Given a ``write``-like function ``writefunc``, which takes an I/O stream as its first argument, ``base64(writefunc, args...)`` @@ -2353,6 +2358,10 @@ Text I/O using the standard ``write`` functions and returns the base64-encoded string. +.. function:: base64decode(string) + + Decodes the base64-encoded ``string`` and returns the obtained bytes. + Multimedia I/O -------------- @@ -6441,6 +6450,14 @@ Internals Evaluates the arguments to the function call, determines their types, and calls the ``code_typed`` function on the resulting expression +.. function:: code_warntype(f, types) + + Returns an array of lowered and type-inferred ASTs for the methods matching the given generic function and type signature. The ASTs are annotated in such a way as to cause "non-leaf" types to be displayed in red. This serves as a warning of potential type instability. Not all non-leaf types are particularly problematic for performance, so the results need to be used judiciously. See :ref:`man-code-warntype` for more information. + +.. function:: @code_warntype + + Evaluates the arguments to the function call, determines their types, and calls the ``code_warntype`` function on the resulting expression + .. function:: code_llvm(f, types) Prints the LLVM bitcodes generated for running the method matching the given generic function and type signature to STDOUT. diff --git a/doc/stdlib/linalg.rst b/doc/stdlib/linalg.rst index 5bec267b1f210..ec5a82d5a9fec 100644 --- a/doc/stdlib/linalg.rst +++ b/doc/stdlib/linalg.rst @@ -209,9 +209,9 @@ Linear algebra functions in Julia are largely implemented by calling functions f .. function:: eigvals(A,[irange,][vl,][vu]) - Returns the eigenvalues of ``A``. If ``A`` is :func:`Symmetric`, - :func:`Hermitian` or :func:`SymTridiagonal`, it is possible to calculate - only a subset of the eigenvalues by specifying either a :func:`UnitRange` + Returns the eigenvalues of ``A``. If ``A`` is :class:`Symmetric`, + :class:`Hermitian` or :class:`SymTridiagonal`, it is possible to calculate + only a subset of the eigenvalues by specifying either a :class:`UnitRange` ``irange`` covering indices of the sorted eigenvalues, or a pair ``vl`` and ``vu`` for the lower and upper boundaries of the eigenvalues. @@ -235,7 +235,7 @@ Linear algebra functions in Julia are largely implemented by calling functions f (The ``k``th eigenvector can be obtained from the slice ``M[:, k]``.) The ``permute`` and ``scale`` keywords are the same as for :func:`eigfact`. - For :func:`SymTridiagonal` matrices, if the optional vector of eigenvalues + For :class:`SymTridiagonal` matrices, if the optional vector of eigenvalues ``eigvals`` is specified, returns the specific corresponding eigenvectors. .. function:: eigfact(A,[irange,][vl,][vu,][permute=true,][scale=true]) -> Eigen @@ -248,9 +248,9 @@ Linear algebra functions in Julia are largely implemented by calling functions f The following functions are available for ``Eigen`` objects: ``inv``, ``det``. - If ``A`` is :func:`Symmetric`, :func:`Hermitian` or :func:`SymTridiagonal`, + If ``A`` is :class:`Symmetric`, :class:`Hermitian` or :class:`SymTridiagonal`, it is possible to calculate only a subset of the eigenvalues by specifying - either a :func:`UnitRange` ``irange`` covering indices of the sorted + either a :class:`UnitRange` ``irange`` covering indices of the sorted eigenvalues or a pair ``vl`` and ``vu`` for the lower and upper boundaries of the eigenvalues. diff --git a/examples/typetree.jl b/examples/typetree.jl index 89278d336557d..fa58a1ccc01d8 100644 --- a/examples/typetree.jl +++ b/examples/typetree.jl @@ -120,3 +120,7 @@ end # print_tree(types_tree) end # module + +if !isinteractive() + TypeTrees.print_tree(TypeTrees.types_tree) +end diff --git a/src/alloc.c b/src/alloc.c index ce6af35c62f67..1fad86481e9b2 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -103,7 +103,7 @@ typedef struct { static size_t jl_new_bits_align(jl_value_t *dt) { if (jl_is_tuple(dt)) { - size_t i, l = jl_tuple_len(dt), align = 0; + size_t i, l = jl_tuple_len(dt), align = 1; for (i = 0; i < l; i++) { size_t l = jl_new_bits_align(jl_tupleref(dt,i)); if (l > align) @@ -605,7 +605,7 @@ jl_datatype_t *jl_new_uninitialized_datatype(size_t nfields) void jl_compute_field_offsets(jl_datatype_t *st) { - size_t sz = 0, alignm = 0; + size_t sz = 0, alignm = 1; int ptrfree = 1; for(size_t i=0; i < jl_tuple_len(st->types); i++) { @@ -674,7 +674,7 @@ jl_datatype_t *jl_new_datatype(jl_sym_t *name, jl_datatype_t *super, t->instance = NULL; t->struct_decl = NULL; t->size = 0; - t->alignment = 0; + t->alignment = 1; if (tn == NULL) { t->name = NULL; diff --git a/src/ast.c b/src/ast.c index e1ae91e7e0a68..767d9bd71151e 100644 --- a/src/ast.c +++ b/src/ast.c @@ -769,7 +769,10 @@ static jl_value_t *copy_ast(jl_value_t *expr, jl_tuple_t *sp, int do_sp) DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr) { - if (jl_is_expr(expr)) { + if (expr == NULL) { + return NULL; + } + else if (jl_is_expr(expr)) { jl_expr_t *e = (jl_expr_t*)expr; size_t i, l = jl_array_len(e->args); jl_expr_t *ne = NULL; diff --git a/src/builtins.c b/src/builtins.c index f298ade52a3eb..7ce82990c90df 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -14,14 +14,8 @@ #include #if defined(_OS_WINDOWS_) #include -#if defined(_COMPILER_INTEL_) -#include -#else -#include -#endif #else #include -#include #endif #include #include "julia.h" diff --git a/src/ccall.cpp b/src/ccall.cpp index 867c13d99b6bf..2ca1f7f0cbd4e 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -71,7 +71,7 @@ extern "C" DLLEXPORT void jl_read_sonames(void) pclose(ldc); } -extern "C" DLLEXPORT const char *jl_lookup_soname(char *pfx, size_t n) +extern "C" DLLEXPORT const char *jl_lookup_soname(const char *pfx, size_t n) { if (!got_sonames) { jl_read_sonames(); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 984a162edc153..792c2dc0b90e3 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1,5 +1,21 @@ // utility procedures used in code generation +#if defined(USE_MCJIT) && defined(_OS_WINDOWS_) +template // for GlobalObject's +static T* addComdat(T *G) +{ + if (imaging_mode) { + Comdat *jl_Comdat = shadow_module->getOrInsertComdat(G->getName()); + jl_Comdat->setSelectionKind(Comdat::NoDuplicates); + G->setComdat(jl_Comdat); + } + return G; +} +#else +template +static T* addComdat(T *G) { return G; } +#endif + // Fixing up references to other modules for MCJIT static GlobalVariable *prepare_global(GlobalVariable *G) { @@ -39,9 +55,14 @@ static llvm::Value *prepare_call(llvm::Value* Callee) return Callee; } +#ifdef LLVM35 +static inline void add_named_global(GlobalObject *gv, void *addr) +#else static inline void add_named_global(GlobalValue *gv, void *addr) +#endif { #ifdef USE_MCJIT + addComdat(gv); sys::DynamicLibrary::AddSymbol(gv->getName(),addr); #else jl_ExecutionEngine->addGlobalMapping(gv,addr); @@ -74,7 +95,7 @@ static GlobalVariable *stringConst(const std::string &txt) (const unsigned char*)txt.c_str(), txt.length()+1)), #endif - vname); + vname); stringConstants[txt] = gv; strno++; } @@ -159,6 +180,8 @@ class FunctionMover : public ValueMaterializer return destModule->getOrInsertFunction(F->getName(),F->getFunctionType()); } if (F->isDeclaration() || F->getParent() != destModule) { + if (F->getName().empty()) + return CloneFunctionProto(F); Function *shadow = srcModule->getFunction(F->getName()); if (shadow != NULL && !shadow->isDeclaration()) { // Not truly external @@ -199,10 +222,12 @@ class FunctionMover : public ValueMaterializer newGV->copyAttributesFrom(GV); if (GV->isDeclaration()) return newGV; - uint64_t addr = jl_mcjmm->getSymbolAddress(GV->getName()); - if (addr != 0) { - newGV->setExternallyInitialized(true); - return newGV; + if (!GV->getName().empty()) { + uint64_t addr = jl_ExecutionEngine->getGlobalValueAddress(GV->getName()); + if (addr != 0) { + newGV->setExternallyInitialized(true); + return newGV; + } } std::map::iterator it; it = llvm_to_jl_value.find(GV); @@ -256,40 +281,42 @@ static void jl_gen_llvm_gv_array(llvm::Module *mod, SmallVector(jl_sysimg_gvars)), - "jl_sysimg_gvars")); - globalvars.push_back(new GlobalVariable( - *mod, - T_size, - true, - GlobalVariable::ExternalLinkage, - ConstantInt::get(T_size,globalUnique+1), - "jl_globalUnique")); + globalvars.push_back(addComdat(new GlobalVariable( + *mod, + atype, + true, + GlobalVariable::ExternalLinkage, + ConstantArray::get(atype, ArrayRef(jl_sysimg_gvars)), + "jl_sysimg_gvars"))); + globalvars.push_back(addComdat(new GlobalVariable( + *mod, + T_size, + true, + GlobalVariable::ExternalLinkage, + ConstantInt::get(T_size,globalUnique+1), + "jl_globalUnique"))); Constant *feature_string = ConstantDataArray::getString(jl_LLVMContext, jl_compileropts.cpu_target); - globalvars.push_back(new GlobalVariable(*mod, - feature_string->getType(), - true, - GlobalVariable::ExternalLinkage, - feature_string, - "jl_sysimg_cpu_target")); + globalvars.push_back(addComdat(new GlobalVariable( + *mod, + feature_string->getType(), + true, + GlobalVariable::ExternalLinkage, + feature_string, + "jl_sysimg_cpu_target"))); // For native also store the cpuid if (strcmp(jl_compileropts.cpu_target,"native") == 0) { uint32_t info[4]; jl_cpuid((int32_t*)info, 1); - globalvars.push_back(new GlobalVariable(*mod, - T_int64, - true, - GlobalVariable::ExternalLinkage, - ConstantInt::get(T_int64,((uint64_t)info[2])|(((uint64_t)info[3])<<32)), - "jl_sysimg_cpu_cpuid")); + globalvars.push_back(addComdat(new GlobalVariable( + *mod, + T_int64, + true, + GlobalVariable::ExternalLinkage, + ConstantInt::get(T_int64,((uint64_t)info[2])|(((uint64_t)info[3])<<32)), + "jl_sysimg_cpu_cpuid"))); } } @@ -314,9 +341,10 @@ static Value *julia_gv(const char *cname, void *addr) std::stringstream gvname; gvname << cname << globalUnique++; // no existing GlobalVariable, create one and store it - GlobalValue *gv = new GlobalVariable(*jl_Module, jl_pvalue_llvmt, + GlobalVariable *gv = new GlobalVariable(*jl_Module, jl_pvalue_llvmt, false, imaging_mode ? GlobalVariable::InternalLinkage : GlobalVariable::ExternalLinkage, ConstantPointerNull::get((PointerType*)jl_pvalue_llvmt), gvname.str()); + addComdat(gv); // make the pointer valid for this session #ifdef USE_MCJIT diff --git a/src/codegen.cpp b/src/codegen.cpp index 7a7e28e93738c..5b956fa2892ea 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1,18 +1,4 @@ #include "platform.h" -/* - * We include here, because somewhere below is included also. - * As a result, Intel C++ Composer generates an error. To prevent this error, we - * include as soon as possible. defines several macros - * (like _INC_MATH, __MATH_H_INCLUDED, __COMPLEX_H_INCLUDED) that prevent - * including (or rather its content). - */ -#if defined(_OS_WINDOWS_) -#if defined(_COMPILER_INTEL_) -#include -#else -#include -#endif -#endif #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS @@ -264,18 +250,10 @@ static GlobalVariable *jlRTLD_DEFAULT_var; #ifdef _OS_WINDOWS_ static GlobalVariable *jlexe_var; static GlobalVariable *jldll_var; -#if defined(_CPU_X86_64_) -#ifdef USE_MCJIT -#if LLVM36 -extern std::unique_ptr createRTDyldMemoryManagerWin(RTDyldMemoryManager *MM); -#else -RTDyldMemoryManager* createRTDyldMemoryManagerWin(RTDyldMemoryManager *MM); -#endif -#else +#if defined(_CPU_X86_64_) && !defined(USE_MCJIT) extern JITMemoryManager* createJITMemoryManagerWin(); #endif -#endif -#endif +#endif //_OS_WINDOWS_ // important functions static Function *jlnew_func; @@ -636,6 +614,15 @@ static void jl_setup_module(Module *m, bool add) jl_ExecutionEngine->addModule(std::unique_ptr(m)); #else jl_ExecutionEngine->addModule(m); +#endif +#if defined(_CPU_X86_64_) && defined(_OS_WINDOWS_) && defined(USE_MCJIT) + ArrayType *atype = ArrayType::get(T_uint32,3); // want 4-byte alignment of 12-bytes of data + (new GlobalVariable(*m, atype, + false, GlobalVariable::InternalLinkage, + ConstantAggregateZero::get(atype), "__UnwindData"))->setSection(".text"); + (new GlobalVariable(*m, atype, + false, GlobalVariable::InternalLinkage, + ConstantAggregateZero::get(atype), "__catchjmp"))->setSection(".text"); #endif } } @@ -891,8 +878,9 @@ static void coverageVisitLine(std::string filename, int line) if (vec.size() <= (size_t)line) vec.resize(line+1, NULL); if (vec[line] == NULL) - vec[line] = new GlobalVariable(*jl_Module, T_int64, false, GlobalVariable::InternalLinkage, - ConstantInt::get(T_int64,0), "lcnt"); + vec[line] = addComdat(new GlobalVariable(*jl_Module, T_int64, false, + GlobalVariable::InternalLinkage, + ConstantInt::get(T_int64,0), "lcnt")); GlobalVariable *v = vec[line]; builder.CreateStore(builder.CreateAdd(builder.CreateLoad(v), ConstantInt::get(T_int64,1)), @@ -970,9 +958,9 @@ static void mallocVisitLine(std::string filename, int line) if (vec.size() <= (size_t)line) vec.resize(line+1, NULL); if (vec[line] == NULL) - vec[line] = new GlobalVariable(*jl_Module, T_int64, false, - GlobalVariable::InternalLinkage, - ConstantInt::get(T_int64,0), "bytecnt"); + vec[line] = addComdat(new GlobalVariable(*jl_Module, T_int64, false, + GlobalVariable::InternalLinkage, + ConstantInt::get(T_int64,0), "bytecnt")); GlobalVariable *v = vec[line]; builder.CreateStore(builder.CreateAdd(builder.CreateLoad(v, true), builder.CreateCall(prepare_call(diff_gc_total_bytes_func))), @@ -3428,6 +3416,7 @@ static Function *gen_jlcall_wrapper(jl_lambda_info_t *lam, jl_expr_t *ast, Funct Function *w = Function::Create(jl_func_sig, Function::ExternalLinkage, funcName.str(), f->getParent()); + addComdat(w); Function::arg_iterator AI = w->arg_begin(); AI++; //const Argument &fArg = *AI++; Value *argArray = AI++; @@ -3664,6 +3653,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) Type *rt = (jlrettype == (jl_value_t*)jl_void_type ? T_void : julia_type_to_llvm(jlrettype)); f = Function::Create(FunctionType::get(rt, fsig, false), Function::ExternalLinkage, funcName.str(), m); + addComdat(f); if (lam->cFunctionObject == NULL) { lam->cFunctionObject = (void*)f; lam->cFunctionID = jl_assign_functionID(f); @@ -3677,6 +3667,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle) else { f = Function::Create(jl_func_sig, Function::ExternalLinkage, funcName.str(), m); + addComdat(f); if (lam->functionObject == NULL) { lam->functionObject = (void*)f; lam->functionID = jl_assign_functionID(f); @@ -4436,10 +4427,10 @@ static void init_julia_llvm_env(Module *m) #if JL_NEED_FLOATTEMP_VAR // Has to be big enough for the biggest LLVM-supported float type jlfloattemp_var = - new GlobalVariable(*m, IntegerType::get(jl_LLVMContext,128), + addComdat(new GlobalVariable(*m, IntegerType::get(jl_LLVMContext,128), false, GlobalVariable::ExternalLinkage, ConstantInt::get(IntegerType::get(jl_LLVMContext,128),0), - "jl_float_temp"); + "jl_float_temp")); #endif std::vector args1(0); @@ -4895,10 +4886,10 @@ extern "C" void jl_init_codegen(void) options.NoFramePointerElimNonLeaf = true; #endif #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) - // tell Win32 to assume the stack is always 8-byte aligned, - // and to ensure that it is 8-byte aligned for out-going calls, + // tell Win32 to assume the stack is always 16-byte aligned, + // and to ensure that it is 16-byte aligned for out-going calls, // to ensure compatibility with GCC codes - options.StackAlignmentOverride = 8; + options.StackAlignmentOverride = 16; #endif #if defined(__APPLE__) && !defined(LLVM34) // turn on JIT support for libunwind to walk the stack @@ -4913,7 +4904,7 @@ extern "C" void jl_init_codegen(void) #ifdef V128_BUG ,"-avx" #endif -#if defined(LLVM35) && defined(_OS_WINDOWS_) +#if defined(LLVM35) && defined(_OS_WINDOWS_) && !defined(LLVM36) ,"-disable-copyprop" // llvm bug 21743 #endif }; @@ -4926,13 +4917,8 @@ extern "C" void jl_init_codegen(void) #endif std::string ErrorStr; eb ->setEngineKind(EngineKind::JIT) -#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_) -#if defined(USE_MCJIT) - .setMCJITMemoryManager(createRTDyldMemoryManagerWin( - new SectionMemoryManager())) -#else +#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_) && !defined(USE_MCJIT) .setJITMemoryManager(createJITMemoryManagerWin()) -#endif #endif .setTargetOptions(options) #if defined(USE_MCJIT) && !defined(LLVM36) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index 084b700b94d5c..1efa5ec69f7f8 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -82,12 +82,13 @@ extern "C" EXCEPTION_DISPOSITION _seh_exception_handler(PEXCEPTION_RECORD Except #endif #include static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnname, - uint8_t *Section, size_t Allocated) + uint8_t *Section, size_t Allocated, uint8_t *UnwindData) { DWORD mod_size = 0; #if defined(_CPU_X86_64_) +#if !defined(USE_MCJIT) uint8_t *catchjmp = Section+Allocated; - uint8_t *UnwindData = (uint8_t*)(((uintptr_t)catchjmp+12+3)&~(uintptr_t)3); + UnwindData = (uint8_t*)(((uintptr_t)catchjmp+12+3)&~(uintptr_t)3); if (!catchjmp[0]) { catchjmp[0] = 0x48; catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [...] @@ -102,26 +103,25 @@ static void create_PRUNTIME_FUNCTION(uint8_t *Code, size_t Size, StringRef fnnam UnwindData[5] = 0x03; // mov RBP, RSP UnwindData[6] = 1; // first instruction UnwindData[7] = 0x50; // push RBP - *(DWORD*)&UnwindData[8] = (DWORD)Allocated; // relative location of catchjmp + *(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - Section); // relative location of catchjmp mod_size = (DWORD)Allocated+48; } -#if !defined(USE_MCJIT) PRUNTIME_FUNCTION tbl = (PRUNTIME_FUNCTION)(UnwindData+12); #else PRUNTIME_FUNCTION tbl = (PRUNTIME_FUNCTION)malloc(sizeof(RUNTIME_FUNCTION)); #endif tbl->BeginAddress = (DWORD)(Code - Section); - tbl->EndAddress = (DWORD)(intptr_t)(Code + Size - Section); - tbl->UnwindData = (DWORD)(intptr_t)(UnwindData - Section); + tbl->EndAddress = (DWORD)(Code - Section + Size); + tbl->UnwindData = (DWORD)(UnwindData - Section); #else // defined(_CPU_X86_64_) - Section = Code; + Section += (uintptr_t)Code; mod_size = Size; #endif if (0) { assert(!jl_in_stackwalk); jl_in_stackwalk = 1; if (mod_size && !SymLoadModuleEx(GetCurrentProcess(), NULL, NULL, NULL, (DWORD64)Section, mod_size, NULL, SLMFLAG_VIRTUAL)) { -#if defined(_CPU_X86_64_) +#if defined(_CPU_X86_64_) && !defined(USE_MCJIT) catchjmp[0] = 0; #endif static int warned = 0; @@ -178,7 +178,7 @@ class JuliaJITEventListener: public JITEventListener size_t Size, const EmittedFunctionDetails &Details) { #if defined(_OS_WINDOWS_) - create_PRUNTIME_FUNCTION((uint8_t*)Code, Size, F.getName(), (uint8_t*)Code, Size); + create_PRUNTIME_FUNCTION((uint8_t*)Code, Size, F.getName(), (uint8_t*)Code, Size, NULL); #endif FuncInfo tmp = {&F, Size, F.getName().str(), std::string(), Details.LineStarts}; info[(size_t)(Code)] = tmp; @@ -213,10 +213,75 @@ class JuliaJITEventListener: public JITEventListener StringRef sName; #endif #ifdef _OS_WINDOWS_ - uint64_t SectionAddr; - uint64_t SectionSize; + uint64_t SectionAddr = 0; + uint64_t SectionSize = 0; + uint64_t SectionAddrCheck = 0; // assert that all of the Sections are at the same location #endif +#if defined(_OS_WINDOWS_) +#if defined(_CPU_X86_64_) + uint8_t *UnwindData = NULL; + uint8_t *catchjmp = NULL; + for (const object::SymbolRef &sym_iter : obj.symbols()) { + sym_iter.getName(sName); + if (sName.equals("__UnwindData")) { + sym_iter.getAddress(Addr); + sym_iter.getSection(Section); +#ifdef LLVM36 + assert(Section->isText()); + Section->getName(sName); + SectionAddr = L.getSectionLoadAddress(sName); + Addr += SectionAddr; +#else + if (Section->isText(isText) || !isText) assert(0 && "!isText"); + Section->getAddress(SectionAddr); +#endif + UnwindData = (uint8_t*)Addr; + if (SectionAddrCheck) + assert(SectionAddrCheck == SectionAddr); + else + SectionAddrCheck = SectionAddr; + } + if (sName.equals("__catchjmp")) { + sym_iter.getAddress(Addr); + sym_iter.getSection(Section); +#ifdef LLVM36 + assert(Section->isText()); + Section->getName(sName); + SectionAddr = L.getSectionLoadAddress(sName); + Addr += SectionAddr; +#else + if (Section->isText(isText) || !isText) assert(0 && "!isText"); + Section->getAddress(SectionAddr); +#endif + catchjmp = (uint8_t*)Addr; + if (SectionAddrCheck) + assert(SectionAddrCheck == SectionAddr); + else + SectionAddrCheck = SectionAddr; + } + } + assert(catchjmp); + assert(UnwindData); + catchjmp[0] = 0x48; + catchjmp[1] = 0xb8; // mov RAX, QWORD PTR [&_seh_exception_handle] + *(uint64_t*)(&catchjmp[2]) = (uint64_t)&_seh_exception_handler; + catchjmp[10] = 0xff; + catchjmp[11] = 0xe0; // jmp RAX + UnwindData[0] = 0x09; // version info, UNW_FLAG_EHANDLER + UnwindData[1] = 4; // size of prolog (bytes) + UnwindData[2] = 2; // count of unwind codes (slots) + UnwindData[3] = 0x05; // frame register (rbp) = rsp + UnwindData[4] = 4; // second instruction + UnwindData[5] = 0x03; // mov RBP, RSP + UnwindData[6] = 1; // first instruction + UnwindData[7] = 0x50; // push RBP + *(DWORD*)&UnwindData[8] = (DWORD)(catchjmp - (uint8_t*)SectionAddr); // relative location of catchjmp +#else // defined(_OS_X86_64_) + uint8_t *UnwindData = NULL; +#endif // defined(_OS_X86_64_) +#endif // defined(_OS_WINDOWS_) + #ifdef LLVM35 for (const object::SymbolRef &sym_iter : obj.symbols()) { sym_iter.getType(SymbolType); @@ -245,22 +310,25 @@ class JuliaJITEventListener: public JITEventListener #endif #elif defined(_OS_WINDOWS_) #if defined(LLVM36) - SectionAddr = Section->getAddress(); SectionSize = Section->getSize(); Section->getName(sName); - Addr += L.getSectionLoadAddress(sName); - SectionAddr += L.getSectionLoadAddress(sName); + SectionAddr = L.getSectionLoadAddress(sName); + Addr += SectionAddr; #else Section->getAddress(SectionAddr); Section->getSize(SectionSize); #endif sym_iter.getName(sName); -#ifndef _CPU_X86_ +#ifdef _CPU_X86_ if (sName[0] == '_') sName = sName.substr(1); #endif + if (SectionAddrCheck) + assert(SectionAddrCheck == SectionAddr); + else + SectionAddrCheck = SectionAddr; create_PRUNTIME_FUNCTION( (uint8_t*)(intptr_t)Addr, (size_t)Size, sName, - (uint8_t*)(intptr_t)SectionAddr, (size_t)SectionSize); + (uint8_t*)(intptr_t)SectionAddr, (size_t)SectionSize, UnwindData); #endif const object::ObjectFile *objfile = #ifdef LLVM36 @@ -428,7 +496,9 @@ void jl_getDylibFunctionInfo(const char **name, size_t *line, const char **filen if (isvalid) { char *fname = ModuleInfo.LoadedImageName; DWORD64 fbase = ModuleInfo.BaseOfImage; +#ifdef LLVM35 size_t msize = ModuleInfo.ImageSize; +#endif *fromC = (fbase != jl_sysimage_base); if (skipC && *fromC) { return; @@ -738,87 +808,6 @@ int jl_get_llvmf_info(size_t fptr, uint64_t *symsize, #if defined(_OS_WINDOWS_) #ifdef USE_MCJIT -#if defined(_CPU_X86_64_) -class RTDyldMemoryManagerWin : public RTDyldMemoryManager { -public: - RTDyldMemoryManagerWin(RTDyldMemoryManager *MM) - : ClientMM(MM) {} - - // Functions deferred to client memory manager - uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, - StringRef SectionName) override { - uint8_t *mem = ClientMM->allocateCodeSection(Size+48, Alignment, SectionID, SectionName); - mem[Size] = 0; - return mem; - } - - uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, StringRef SectionName, - bool IsReadOnly) override { - return ClientMM->allocateDataSection(Size, Alignment, - SectionID, SectionName, IsReadOnly); - } - - void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO, - uintptr_t DataSizeRW) override { - return ClientMM->reserveAllocationSpace(CodeSize+48, DataSizeRO, DataSizeRW); - } - - bool needsToReserveAllocationSpace() override { - return ClientMM->needsToReserveAllocationSpace(); - } - - void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, - size_t Size) override { - ClientMM->registerEHFrames(Addr, LoadAddr, Size); - } - - void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, - size_t Size) override { - ClientMM->deregisterEHFrames(Addr, LoadAddr, Size); - } - - uint64_t getSymbolAddress(const std::string &Name) override { - return ClientMM->getSymbolAddress(Name); - } - - void notifyObjectLoaded(ExecutionEngine *EE, -#ifdef LLVM36 - const object::ObjectFile &Obj) override { -#else - const ObjectImage *Obj) override { -#endif - ClientMM->notifyObjectLoaded(EE, Obj); - } - - - void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true) override { - return ClientMM->getPointerToNamedFunction(Name,AbortOnFailure); - } - - bool finalizeMemory(std::string *ErrMsg = nullptr) override { - return ClientMM->finalizeMemory(ErrMsg); - } - -private: - std::unique_ptr ClientMM; -}; -#if LLVM36 -std::unique_ptr createRTDyldMemoryManagerWin(RTDyldMemoryManager *MM) { - return std::unique_ptr( - new RTDyldMemoryManagerWin(MM)); -} -#else -RTDyldMemoryManager* createRTDyldMemoryManagerWin(RTDyldMemoryManager *MM) { - return new RTDyldMemoryManagerWin(MM); -} -#endif -#else -RTDyldMemoryManager* createRTDyldMemoryManagerWin(RTDyldMemoryManager *MM) { - return NULL; -} extern "C" DWORD64 jl_getUnwindInfo(ULONG64 dwAddr) { @@ -829,7 +818,7 @@ DWORD64 jl_getUnwindInfo(ULONG64 dwAddr) } return 0; } -#endif + #else //ifdef USE_MCJIT #if defined(_CPU_X86_64_) // Custom memory manager for exception handling on Windows diff --git a/src/dlload.c b/src/dlload.c index 4e8070b3b1e7c..5d2f9b4739400 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -75,7 +75,7 @@ DLLEXPORT int jl_uv_dlopen(const char *filename, jl_uv_libhandle lib_, unsigned #endif } -static uv_lib_t *jl_load_dynamic_library_(char *modname, unsigned flags, int throw_err) +static uv_lib_t *jl_load_dynamic_library_(const char *modname, unsigned flags, int throw_err) { int error; char *ext; @@ -153,17 +153,17 @@ static uv_lib_t *jl_load_dynamic_library_(char *modname, unsigned flags, int thr return handle; } -jl_uv_libhandle jl_load_dynamic_library_e(char *modname, unsigned flags) +jl_uv_libhandle jl_load_dynamic_library_e(const char *modname, unsigned flags) { return (jl_uv_libhandle) jl_load_dynamic_library_(modname, flags, 0); } -jl_uv_libhandle jl_load_dynamic_library(char *modname, unsigned flags) +jl_uv_libhandle jl_load_dynamic_library(const char *modname, unsigned flags) { return (jl_uv_libhandle) jl_load_dynamic_library_(modname, flags, 1); } -void *jl_dlsym_e(jl_uv_libhandle handle, char *symbol) +void *jl_dlsym_e(jl_uv_libhandle handle, const char *symbol) { void *ptr; int error=uv_dlsym((uv_lib_t *) handle, symbol, &ptr); @@ -171,7 +171,7 @@ void *jl_dlsym_e(jl_uv_libhandle handle, char *symbol) return ptr; } -void *jl_dlsym(jl_uv_libhandle handle, char *symbol) +void *jl_dlsym(jl_uv_libhandle handle, const char *symbol) { void *ptr; int error = uv_dlsym((uv_lib_t *) handle, symbol, &ptr); @@ -183,7 +183,7 @@ void *jl_dlsym(jl_uv_libhandle handle, char *symbol) #ifdef _OS_WINDOWS_ //Look for symbols in win32 libraries -char *jl_dlfind_win32(char *f_name) +char *jl_dlfind_win32(const char *f_name) { if (jl_dlsym_e(jl_exe_handle, f_name)) return (char*)1; diff --git a/src/init.c b/src/init.c index ae0ded2a64603..28e960bf98d88 100644 --- a/src/init.c +++ b/src/init.c @@ -101,6 +101,7 @@ jl_compileropts_t jl_compileropts = { NULL, // julia_home JL_COMPILEROPT_COMPILE_DEFAULT, 0, // opt_level 1, // depwarn + 1 // can_inline }; int jl_boot_file_loaded = 0; @@ -125,21 +126,55 @@ static void jl_find_stack_bottom(void) } #ifdef _OS_WINDOWS_ -void __cdecl fpe_handler(int arg, int num) +static char *strsignal(int sig) { - (void)arg; - fpreset(); - signal(SIGFPE, (void (__cdecl *)(int))fpe_handler); - switch(num) { - case _FPE_INVALID: - case _FPE_OVERFLOW: - case _FPE_UNDERFLOW: - default: - jl_errorf("Unexpected FPE Error 0x%X", num); + switch (sig) { + case SIGINT: return "SIGINT"; break; + case SIGILL: return "SIGILL"; break; + case SIGABRT_COMPAT: return "SIGABRT_COMPAT"; break; + case SIGFPE: return "SIGFPE"; break; + case SIGSEGV: return "SIGSEGV"; break; + case SIGTERM: return "SIGTERM"; break; + case SIGBREAK: return "SIGBREAK"; break; + case SIGABRT: return "SIGABRT"; break; + } + return "?"; +} + +void __cdecl crt_sig_handler(int sig, int num) +{ + switch (sig) { + case SIGFPE: + fpreset(); + signal(SIGFPE, (void (__cdecl *)(int))crt_sig_handler); + switch(num) { + case _FPE_INVALID: + case _FPE_OVERFLOW: + case _FPE_UNDERFLOW: + default: + jl_errorf("Unexpected FPE Error 0x%X", num); + break; + case _FPE_ZERODIVIDE: + jl_throw(jl_diverror_exception); + break; + } break; - case _FPE_ZERODIVIDE: - jl_throw(jl_diverror_exception); + case SIGINT: + signal(SIGINT, (void (__cdecl *)(int))crt_sig_handler); + if (exit_on_sigint) jl_exit(0); + if (jl_defer_signal) { + jl_signal_pending = sig; + } + else { + jl_signal_pending = 0; + jl_throw(jl_interrupt_exception); + } break; + default: // SIGSEGV, (SSIGTERM, IGILL) + ios_printf(ios_stderr,"\nsignal (%d): %s\n", sig, strsignal(sig)); + bt_size = rec_backtrace(bt_data, MAX_BT_SIZE); + jlbacktrace(); + raise(sig); } } #else @@ -259,7 +294,7 @@ static BOOL WINAPI sigint_handler(DWORD wsig) //This needs winapi types to guara { if (exit_on_sigint) jl_exit(0); int sig; - //windows signals use different numbers from unix + //windows signals use different numbers from unix (raise) switch(wsig) { case CTRL_C_EVENT: sig = SIGINT; break; //case CTRL_BREAK_EVENT: sig = SIGTERM; break; @@ -1113,10 +1148,26 @@ void _julia_init(JL_IMAGE_SEARCH rel) jl_exit(1); } #else // defined(_OS_WINDOWS_) - if (signal(SIGFPE, (void (__cdecl *)(int))fpe_handler) == SIG_ERR) { + if (signal(SIGFPE, (void (__cdecl *)(int))crt_sig_handler) == SIG_ERR) { JL_PRINTF(JL_STDERR, "fatal error: Couldn't set SIGFPE\n"); jl_exit(1); } + if (signal(SIGILL, (void (__cdecl *)(int))crt_sig_handler) == SIG_ERR) { + JL_PRINTF(JL_STDERR, "fatal error: Couldn't set SIGILL\n"); + jl_exit(1); + } + if (signal(SIGINT, (void (__cdecl *)(int))crt_sig_handler) == SIG_ERR) { + JL_PRINTF(JL_STDERR, "fatal error: Couldn't set SIGINT\n"); + jl_exit(1); + } + if (signal(SIGSEGV, (void (__cdecl *)(int))crt_sig_handler) == SIG_ERR) { + JL_PRINTF(JL_STDERR, "fatal error: Couldn't set SIGSEGV\n"); + jl_exit(1); + } + if (signal(SIGTERM, (void (__cdecl *)(int))crt_sig_handler) == SIG_ERR) { + JL_PRINTF(JL_STDERR, "fatal error: Couldn't set SIGTERM\n"); + jl_exit(1); + } SetUnhandledExceptionFilter(exception_handler); #endif diff --git a/src/jl_uv.c b/src/jl_uv.c index 6b68a895765e5..0e2e9bfe944c2 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -508,7 +508,7 @@ DLLEXPORT int jl_fs_close(int handle) } //units are in ms -DLLEXPORT int jl_puts(char *str, uv_stream_t *stream) +DLLEXPORT int jl_puts(const char *str, uv_stream_t *stream) { if (!stream) return 0; return jl_write(stream,str,strlen(str)); diff --git a/src/jlapi.c b/src/jlapi.c index a93201c6586fc..59a3733d1f4bc 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -22,7 +22,7 @@ DLLEXPORT char * __cdecl basename(char *); #include #endif -DLLEXPORT void *jl_eval_string(char *str); +DLLEXPORT void *jl_eval_string(const char *str); int jl_is_initialized(void) { return jl_main_module!=NULL; } @@ -32,7 +32,7 @@ int jl_is_initialized(void) { return jl_main_module!=NULL; } // Second argument is the path of a system image file (*.ji) relative to the // first argument path, or relative to the default julia home dir. The default // is something like ../lib/julia/sys.ji -DLLEXPORT void jl_init_with_image(char *julia_home_dir, char *image_relative_path) +DLLEXPORT void jl_init_with_image(const char *julia_home_dir, const char *image_relative_path) { if (jl_is_initialized()) return; libsupport_init(); @@ -49,12 +49,12 @@ DLLEXPORT void jl_init_with_image(char *julia_home_dir, char *image_relative_pat jl_exception_clear(); } -DLLEXPORT void jl_init(char *julia_home_dir) +DLLEXPORT void jl_init(const char *julia_home_dir) { jl_init_with_image(julia_home_dir, NULL); } -DLLEXPORT void *jl_eval_string(char *str) +DLLEXPORT void *jl_eval_string(const char *str) { jl_value_t *r; JL_TRY { @@ -259,22 +259,22 @@ DLLEXPORT jl_value_t *jl_get_image_file(void) return jl_cstr_to_string(jl_compileropts.image_file); } -DLLEXPORT const int jl_ver_major(void) +DLLEXPORT int jl_ver_major(void) { return JULIA_VERSION_MAJOR; } -DLLEXPORT const int jl_ver_minor(void) +DLLEXPORT int jl_ver_minor(void) { return JULIA_VERSION_MINOR; } -DLLEXPORT const int jl_ver_patch(void) +DLLEXPORT int jl_ver_patch(void) { return JULIA_VERSION_PATCH; } -DLLEXPORT const int jl_ver_is_release(void) +DLLEXPORT int jl_ver_is_release(void) { return JULIA_VERSION_IS_RELEASE; } diff --git a/src/jltypes.c b/src/jltypes.c index 7d4d53cee951c..7f82bac07855e 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -1969,7 +1969,8 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_value_t **env, size_t n, ndt->instance = NULL; ndt->uid = 0; ndt->struct_decl = NULL; - ndt->size = ndt->alignment = 0; + ndt->size = 0; + ndt->alignment = 1; ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)dt->super, env,n,stack, 1); ftypes = dt->types; if (ftypes != NULL) { diff --git a/src/julia.h b/src/julia.h index 52f2f96f11abf..011f4b5415018 100644 --- a/src/julia.h +++ b/src/julia.h @@ -861,10 +861,10 @@ typedef enum { //JL_IMAGE_LIBJULIA = 2, } JL_IMAGE_SEARCH; DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel); -DLLEXPORT void jl_init(char *julia_home_dir); -DLLEXPORT void jl_init_with_image(char *julia_home_dir, char *image_relative_path); +DLLEXPORT void jl_init(const char *julia_home_dir); +DLLEXPORT void jl_init_with_image(const char *julia_home_dir, const char *image_relative_path); DLLEXPORT int jl_is_initialized(void); -DLLEXPORT int julia_trampoline(int argc, char *argv[], int (*pmain)(int ac,char *av[])); +DLLEXPORT int julia_trampoline(int argc, const char *argv[], int (*pmain)(int ac,char *av[])); DLLEXPORT void jl_atexit_hook(void); DLLEXPORT void NORETURN jl_exit(int status); @@ -885,7 +885,7 @@ jl_value_t *jl_parse_next(void); DLLEXPORT jl_value_t *jl_load_file_string(const char *text, char *filename); DLLEXPORT jl_value_t *jl_expand(jl_value_t *expr); jl_lambda_info_t *jl_wrap_expr(jl_value_t *expr); -DLLEXPORT void *jl_eval_string(char *str); +DLLEXPORT void *jl_eval_string(const char *str); // external libraries enum JL_RTLD_CONSTANT { @@ -899,17 +899,17 @@ enum JL_RTLD_CONSTANT { #define JL_RTLD_DEFAULT (JL_RTLD_LAZY | JL_RTLD_DEEPBIND) typedef void *jl_uv_libhandle; // uv_lib_t* (avoid uv.h dependency) -DLLEXPORT jl_uv_libhandle jl_load_dynamic_library(char *fname, unsigned flags); -DLLEXPORT jl_uv_libhandle jl_load_dynamic_library_e(char *fname, unsigned flags); -DLLEXPORT void *jl_dlsym_e(jl_uv_libhandle handle, char *symbol); -DLLEXPORT void *jl_dlsym(jl_uv_libhandle handle, char *symbol); +DLLEXPORT jl_uv_libhandle jl_load_dynamic_library(const char *fname, unsigned flags); +DLLEXPORT jl_uv_libhandle jl_load_dynamic_library_e(const char *fname, unsigned flags); +DLLEXPORT void *jl_dlsym_e(jl_uv_libhandle handle, const char *symbol); +DLLEXPORT void *jl_dlsym(jl_uv_libhandle handle, const char *symbol); DLLEXPORT int jl_uv_dlopen(const char *filename, jl_uv_libhandle lib, unsigned flags); DLLEXPORT jl_uv_libhandle jl_wrap_raw_dl_handle(void *handle); -char *jl_dlfind_win32(char *name); +char *jl_dlfind_win32(const char *name); DLLEXPORT int add_library_mapping(char *lib, void *hnd); #if defined(__linux__) || defined(__FreeBSD__) -DLLEXPORT const char *jl_lookup_soname(char *pfx, size_t n); +DLLEXPORT const char *jl_lookup_soname(const char *pfx, size_t n); #endif // compiler @@ -918,7 +918,7 @@ DLLEXPORT jl_value_t *jl_toplevel_eval(jl_value_t *v); DLLEXPORT jl_value_t *jl_toplevel_eval_in(jl_module_t *m, jl_value_t *ex); jl_value_t *jl_eval_global_var(jl_module_t *m, jl_sym_t *e); DLLEXPORT jl_value_t *jl_load(const char *fname); -jl_value_t *jl_parse_eval_all(char *fname); +jl_value_t *jl_parse_eval_all(const char *fname); jl_value_t *jl_interpret_toplevel_thunk(jl_lambda_info_t *lam); jl_value_t *jl_interpret_toplevel_thunk_with(jl_lambda_info_t *lam, jl_value_t **loc, size_t nl); @@ -1107,8 +1107,10 @@ DLLEXPORT extern volatile sig_atomic_t jl_defer_signal; #define JL_SIGATOMIC_END() \ do { \ jl_defer_signal--; \ - if (jl_defer_signal == 0 && jl_signal_pending != 0) \ - raise(jl_signal_pending); \ + if (jl_defer_signal == 0 && jl_signal_pending != 0) { \ + jl_signal_pending = 0; \ + jl_throw(jl_interrupt_exception); \ + } \ } while(0) DLLEXPORT void restore_signals(void); @@ -1261,7 +1263,7 @@ DLLEXPORT int jl_idle_start(uv_idle_t *idle); DLLEXPORT int jl_idle_stop(uv_idle_t *idle); DLLEXPORT int jl_putc(char c, uv_stream_t *stream); -DLLEXPORT int jl_puts(char *str, uv_stream_t *stream); +DLLEXPORT int jl_puts(const char *str, uv_stream_t *stream); DLLEXPORT int jl_pututf8(uv_stream_t *s, uint32_t wchar); DLLEXPORT uv_timer_t *jl_make_timer(uv_loop_t *loop, jl_value_t *julia_struct); @@ -1331,6 +1333,7 @@ typedef struct { int8_t compile_enabled; int8_t opt_level; int8_t depwarn; + int8_t can_inline; } jl_compileropts_t; extern DLLEXPORT jl_compileropts_t jl_compileropts; @@ -1354,10 +1357,10 @@ extern DLLEXPORT jl_compileropts_t jl_compileropts; // Version information #include "julia_version.h" -DLLEXPORT extern const int jl_ver_major(void); -DLLEXPORT extern const int jl_ver_minor(void); -DLLEXPORT extern const int jl_ver_patch(void); -DLLEXPORT extern const int jl_ver_is_release(void); +DLLEXPORT extern int jl_ver_major(void); +DLLEXPORT extern int jl_ver_minor(void); +DLLEXPORT extern int jl_ver_patch(void); +DLLEXPORT extern int jl_ver_is_release(void); DLLEXPORT extern const char* jl_ver_string(void); #ifdef __cplusplus diff --git a/src/support/dtypes.h b/src/support/dtypes.h index 66b74fe100a03..11a288bc7ea07 100644 --- a/src/support/dtypes.h +++ b/src/support/dtypes.h @@ -4,6 +4,11 @@ #include #include // double include of stddef.h fixes #3421 #include +#if defined(_COMPILER_INTEL_) +#include +#else +#include +#endif #include "platform.h" @@ -173,14 +178,14 @@ typedef uptrint_t u_ptrint_t; #define S32_MIN (-S32_MAX - 1L) #define BIT31 0x80000000 -extern double D_PNAN; -extern double D_NNAN; -extern double D_PINF; -extern double D_NINF; -extern float F_PNAN; -extern float F_NNAN; -extern float F_PINF; -extern float F_NINF; +#define D_PNAN ((double)+NAN) +#define D_NNAN ((double)-NAN) +#define D_PINF ((double)+INFINITY) +#define D_NINF ((double)-INFINITY) +#define F_PNAN ((float)+NAN) +#define F_NNAN ((float)-NAN) +#define F_PINF ((float)+INFINITY) +#define F_NINF ((float)-INFINITY) typedef enum { T_INT8, T_UINT8, T_INT16, T_UINT16, T_INT32, T_UINT32, T_INT64, T_UINT64, T_FLOAT, T_DOUBLE } numerictype_t; diff --git a/src/support/libsupportinit.c b/src/support/libsupportinit.c index 2d3f3b4828c77..197177bccbfdb 100644 --- a/src/support/libsupportinit.c +++ b/src/support/libsupportinit.c @@ -1,16 +1,10 @@ #include -#include #include "libsupport.h" #ifdef __cplusplus extern "C" { #endif -double D_PNAN; -double D_NNAN; -double D_PINF; -double D_NINF; - static int isInitialized = 0; void libsupport_init(void) @@ -24,10 +18,6 @@ void libsupport_init(void) ios_init_stdstreams(); - D_PNAN = +NAN; - D_NNAN = -NAN; - D_PINF = +INFINITY; - D_NINF = -INFINITY; isInitialized=1; } } diff --git a/src/toplevel.c b/src/toplevel.c index bb45c021611ca..82e3dd03e3d67 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -522,7 +522,7 @@ jl_value_t *jl_toplevel_eval(jl_value_t *v) } // repeatedly call jl_parse_next and eval everything -jl_value_t *jl_parse_eval_all(char *fname) +jl_value_t *jl_parse_eval_all(const char *fname) { //jl_printf(JL_STDERR, "***** loading %s\n", fname); int last_lineno = jl_lineno; diff --git a/test/base64.jl b/test/base64.jl new file mode 100644 index 0000000000000..5c360b6ced05c --- /dev/null +++ b/test/base64.jl @@ -0,0 +1,41 @@ + +const inputText = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure." +const encodedMaxLine76 = +"""TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz +IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg +dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu +dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo +ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=""" + +# Encode and decode +fname = tempname() +f = open(fname, "w") +opipe = Base64EncodePipe(f) +write(opipe,inputText) +close(opipe) +close(f) +f = open(fname, "r") +ipipe = Base64DecodePipe(f) +@test readall(ipipe) == inputText +close(ipipe) +close(f) +rm(fname) + +# Encode to string and decode +@test base64decode(base64encode(inputText)) == inputText + +# Decode with max line chars = 76 and padding +ipipe = Base64DecodePipe(IOBuffer(encodedMaxLine76)) +@test readall(ipipe) == inputText + +# Decode with max line chars = 76 and no padding +ipipe = Base64DecodePipe(IOBuffer(encodedMaxLine76[1:end-1])) +@test readall(ipipe) == inputText + +# Decode with two padding characters ("==") +ipipe = Base64DecodePipe(IOBuffer(string(encodedMaxLine76[1:end-2],"=="))) +@test readall(ipipe) == inputText[1:end-1] + +# Test incorrect format +ipipe = Base64DecodePipe(IOBuffer(encodedMaxLine76[1:end-3])) +@test_throws ErrorException readall(ipipe) diff --git a/test/collections.jl b/test/collections.jl index d546d1733468a..90d7b3d2c372e 100644 --- a/test/collections.jl +++ b/test/collections.jl @@ -236,6 +236,12 @@ for d in (Dict("\n" => "\n", "1" => "\n", "\n" => "2"), @test !isempty(summary(values(d))) end +# issue #9463 +type Alpha end +Base.show(io::IO, ::Alpha) = print(io,"α") +sbuff = IOBuffer() +Base.showdict(sbuff, Dict(Alpha()=>1), limit=true, sz=(10,20)) +@test !contains(bytestring(sbuff), "…") # issue #2540 d = Dict{Any,Any}([x => 1 for x in ['a', 'b', 'c']]) diff --git a/test/core.jl b/test/core.jl index 9350e0d2635ba..202e3973af0be 100644 --- a/test/core.jl +++ b/test/core.jl @@ -712,6 +712,24 @@ begin @test typeof(b) === SI{1,-2,1} end +# pointer arithmetic +begin + local a,b,c + a = C_NULL + b = C_NULL + 1 + c = C_NULL - 1 + + @test a != b != c + @test UInt(a) == 0 + @test UInt(b) == 1 + @test UInt(c) == typemax(UInt) + + @test b - a == -(a - b) == 1 + @test c - a == -(a - c) == typemax(UInt) + @test c - b == -(b - c) == typemax(UInt) - 1 + @test a < b < c +end + # pull request 1270 begin local a,p, a2,p2 @@ -1976,3 +1994,32 @@ function f9134() end end @test_throws UndefVarError f9134() + +# issue #9475 +module I9475 + arr = Array(Any, 1) + @eval @eval $arr[1] = 1 +end + +# issue #9520 +f9520a(::Any, ::Any, args...) = 15 +f9520b(::Any, ::Any, ::Any, args...) = 23 +f9520c(::Any, ::Any, ::Any, ::Any, ::Any, ::Any, args...) = 46 +@test invoke(f9520a, (Any, Any), 1, 2) == 15 +@test invoke(f9520a, (Any, Any, Any), 1, 2, 3) == 15 +@test invoke(f9520b, (Any, Any, Any), 1, 2, 3) == 23 +@test invoke(f9520b, (Any, Any, Any, Any, Any, Any), 1, 2, 3, 4, 5, 6) == 23 +@test invoke(f9520c, (Any, Any, Any, Any, Any, Any), 1, 2, 3, 4, 5, 6) == 46 +@test invoke(f9520c, (Any, Any, Any, Any, Any, Any, Any), 1, 2, 3, 4, 5, 6, 7) == 46 + +# jl_new_bits testing +let x = [1,2,3] + @test ccall(:jl_new_bits, Any, (Any,Ptr{Void},), Int, x) === 1 + @test ccall(:jl_new_bits, Any, (Any,Ptr{Void},), Complex{Int}, x) === 1+2im + @test ccall(:jl_new_bits, Any, (Any,Ptr{Void},), NTuple{3,Int}, x) === (1,2,3) + @test ccall(:jl_new_bits, Any, (Any,Ptr{Void},), (Int,Int,Int), x) === (1,2,3) + @test (ccall(:jl_new_bits, Any, (Any,Ptr{Void},), (Int16,(Void,),Int8,(),Int,Void,Int), x)::Tuple)[[2,4,5,6,7]] === ((nothing,),(),2,nothing,3) +end + +# sig 2 is SIGINT per the POSIX.1-1990 standard +@test_throws InterruptException ccall(:raise, Void, (Cint,), 2) diff --git a/test/linalg/givens.jl b/test/linalg/givens.jl new file mode 100644 index 0000000000000..945f5d4157124 --- /dev/null +++ b/test/linalg/givens.jl @@ -0,0 +1,34 @@ +let +debug = false + +# Test givens rotations +for elty in (Float32, Float64, Complex64, Complex128) + + debug && println("elty is $elty") + + if elty <: Real + A = convert(Matrix{elty}, randn(10,10)) + else + A = convert(Matrix{elty}, complex(randn(10,10),randn(10,10))) + end + Ac = copy(A) + R = Base.LinAlg.Rotation(Base.LinAlg.Givens{elty}[]) + for j = 1:8 + for i = j+2:10 + G, _ = givens(A, j+1, i, j) + A_mul_B!(G, A) + A_mul_Bc!(A, G) + A_mul_B!(G, R) + + # test transposes + @test_approx_eq ctranspose(G)*G*eye(10) eye(elty, 10) + @test_approx_eq ctranspose(R)*(R*eye(10)) eye(elty, 10) + @test_throws ErrorException transpose(G) + @test_throws ErrorException transpose(R) + end + end + @test_approx_eq abs(A) abs(hessfact(Ac)[:H]) + @test_approx_eq norm(R*eye(elty, 10)) one(elty) + +end +end #let \ No newline at end of file diff --git a/test/linalg1.jl b/test/linalg1.jl index eb80074d358cf..9997826b32b63 100644 --- a/test/linalg1.jl +++ b/test/linalg1.jl @@ -66,6 +66,11 @@ debug && println("(Automatic) upper Cholesky factor") apos = asym[1,1] # test chol(x::Number), needs x>0 @test_approx_eq cholfact(apos).UL √apos + # test chol of 2x2 Strang matrix + S = convert(AbstractMatrix{eltya},full(SymTridiagonal([2,2],[-1]))) + U = Bidiagonal([2,sqrt(eltya(3))],[-1],true) / sqrt(eltya(2)) + @test_approx_eq full(chol(S)) full(U) + debug && println("lower Cholesky factor") lapd = cholfact(apd, :L) @test_approx_eq full(lapd) apd diff --git a/test/linalg2.jl b/test/linalg2.jl index 2a6739bf8a3c6..e65c6aa6a147a 100644 --- a/test/linalg2.jl +++ b/test/linalg2.jl @@ -170,27 +170,6 @@ for elty in (Complex64, Complex128) @test_approx_eq triu(LinAlg.BLAS.her2k('U','C',U,V)) triu(U'*V + V'*U) end -# Test givens rotations -for elty in (Float32, Float64, Complex64, Complex128) - if elty <: Real - A = convert(Matrix{elty}, randn(10,10)) - else - A = convert(Matrix{elty}, complex(randn(10,10),randn(10,10))) - end - Ac = copy(A) - R = Base.LinAlg.Rotation(Base.LinAlg.Givens{elty}[]) - for j = 1:8 - for i = j+2:10 - G = givens(A, j+1, i, j) - A_mul_B!(G, A) - A_mul_Bc!(A, G) - A_mul_B!(G, R) - end - end - @test_approx_eq abs(A) abs(hessfact(Ac)[:H]) - @test_approx_eq norm(R*eye(elty, 10)) one(elty) -end - # Test gradient for elty in (Int32, Int64, Float32, Float64, Complex64, Complex128) if elty <: Real diff --git a/test/linalg4.jl b/test/linalg4.jl index c13e3693d55a3..29187946f5aa8 100644 --- a/test/linalg4.jl +++ b/test/linalg4.jl @@ -201,6 +201,16 @@ for elty in (Float32, Float64, Complex{Float32}, Complex{Float64}) end end +# Because transpose(x) == x +@test_throws ErrorException transpose(qrfact(randn(3,3))) +@test_throws ErrorException ctranspose(qrfact(randn(3,3))) +@test_throws ErrorException transpose(qrfact(randn(3,3), pivot = false)) +@test_throws ErrorException ctranspose(qrfact(randn(3,3), pivot = false)) +@test_throws ErrorException transpose(qrfact(big(randn(3,3)))) +@test_throws ErrorException ctranspose(qrfact(big(randn(3,3)))) +@test_throws ErrorException transpose(sub(sprandn(10, 10, 0.3), 1:4, 1:4)) +@test_throws ErrorException ctranspose(sub(sprandn(10, 10, 0.3), 1:4, 1:4)) + # Issue #7933 A7933 = [1 2; 3 4] B7933 = copy(A7933) diff --git a/test/lineedit.jl b/test/lineedit.jl index b23a5fa9b07cf..0e12a0d2326c6 100644 --- a/test/lineedit.jl +++ b/test/lineedit.jl @@ -46,6 +46,161 @@ run_test(test3_dict,IOBuffer("aab")) @test a_bar == 2 @test b_bar == 1 +# Multiple spellings in the same keymap +const test_keymap_1 = Dict( + "^C" => (o...)->1, + "\\C-C" => (o...)->2 +) + +@test_throws ErrorException LineEdit.keymap([test_keymap_1]) + +a_foo = a_bar = 0 + +const test_keymap_2 = Dict( + "abc" => (o...)->(global a_foo = 1) +) + +const test_keymap_3 = Dict( + "a" => (o...)->(global a_foo = 2), + "bc" => (o...)->(global a_bar = 3) +) + +function keymap_fcn(keymaps) + d = LineEdit.keymap(keymaps) + f = buf->(LineEdit.match_input(d, nothing, buf)(nothing,nothing)) +end + +let f = keymap_fcn([test_keymap_3, test_keymap_2]) + buf = IOBuffer("abc") + f(buf); f(buf) + @test a_foo == 2 + @test a_bar == 3 + @test eof(buf) +end + +# Eager redirection when the redirected-to behavior is changed. + +a_foo = 0 + +const test_keymap_4 = Dict( + "a" => (o...)->(global a_foo = 1), + "b" => "a", + "c" => (o...)->(global a_foo = 2), +) + +const test_keymap_5 = Dict( + "a" => (o...)->(global a_foo = 3), + "d" => "c" +) + +let f = keymap_fcn([test_keymap_5, test_keymap_4]) + buf = IOBuffer("abd") + f(buf) + @test a_foo == 3 + f(buf) + @test a_foo == 1 + f(buf) + @test a_foo == 2 + @test eof(buf) +end + +# Eager redirection with cycles + +const test_cycle = Dict( + "a" => "b", + "b" => "a" +) + +@test_throws ErrorException keymap([test_cycle]) + +# Lazy redirection with Cycles + +const level1 = Dict( + "a" => LineEdit.KeyAlias("b") +) + +const level2a = Dict( + "b" => "a" +) + +const level2b = Dict( + "b" => LineEdit.KeyAlias("a") +) + +@test_throws ErrorException keymap([level2a,level1]) +@test_throws ErrorException keymap([level2b,level1]) + +# Lazy redirection functionality test + +a_foo = 0 + +const test_keymap_6 = Dict( + "a" => (o...)->(global a_foo = 1), + "b" => LineEdit.KeyAlias("a"), + "c" => (o...)->(global a_foo = 2), +) + +const test_keymap_7 = Dict( + "a" => (o...)->(global a_foo = 3), + "d" => "c" +) + +let f = keymap_fcn([test_keymap_7, test_keymap_6]) + buf = IOBuffer("abd") + f(buf) + @test a_foo == 3 + a_foo = 0 + f(buf) + @test a_foo == 3 + f(buf) + @test a_foo == 2 + @test eof(buf) +end + +# Test requiring postprocessing (see conflict fixing in LineEdit.jl ) + +global path1 = 0 +global path2 = 0 +global path3 = 0 + +const test_keymap_8 = Dict( + "**" => (o...)->(global path1 += 1), + "ab" => (o...)->(global path2 += 1), + "cd" => (o...)->(global path3 += 1), + "d" => (o...)->(error("This is not the key you're looking for")) +) + +let f = keymap_fcn([test_keymap_8]) + buf = IOBuffer("bbabaccd") + f(buf) + @test path1 == 1 + f(buf) + @test path2 == 1 + f(buf) + @test path1 == 2 + f(buf) + @test path3 == 1 + @test eof(buf) +end + +global path1 = 0 +global path2 = 0 + +const test_keymap_9 = Dict( + "***" => (o...)->(global path1 += 1), + "*a*" => (o...)->(global path2 += 1) +) + +let f = keymap_fcn([test_keymap_9]) + buf = IOBuffer("abaaaa") + f(buf) + @test path1 == 1 + f(buf) + @test path2 == 1 + @test eof(buf) +end + + ## edit_move{left,right} ## buf = IOBuffer("a\na\na\n") seek(buf, 0) diff --git a/test/nullable.jl b/test/nullable.jl index dc4b1650b0626..42ef7f740427e 100644 --- a/test/nullable.jl +++ b/test/nullable.jl @@ -243,3 +243,9 @@ for T in types @test !isnull(x1.v) @test get(x1.v, one(T)) === one(T) end + +# issue #9462 +for T in types + @test isa(convert(Nullable{Number}, Nullable(one(T))), Nullable{Number}) + @test isa(convert(Nullable{Any}, Nullable(one(T))), Nullable{Any}) +end diff --git a/test/random.jl b/test/random.jl index 33be81ec9d35c..e43df786e535a 100644 --- a/test/random.jl +++ b/test/random.jl @@ -237,7 +237,7 @@ let mt = MersenneTwister(0) -3482609696641744459568613291754091152,float16(0.03125),0.68733835f0][i] @test B[end] == Any[49,0x65,-3725,0x719d,814246081,0xdf61843a,-3010919637398300844,0x61b367cf8810985d, - -33032345278809823492812856023466859769,float16(0.458),0.51829386f0][i] + -33032345278809823492812856023466859769,float16(0.95),0.51829386f0][i] end srand(mt,0) @@ -299,3 +299,17 @@ for rng in ([], [MersenneTwister()], [RandomDevice()]) end end end + +# test uniform distribution of floats +let bins = [prevfloat(0.0):0.25:1.0] + for rng in [srand(MersenneTwister()), RandomDevice()] + for T in [Float16,Float32,Float64] + # array version + _, counts = hist(rand(rng, T, 2000), bins) + @test minimum(counts) > 300 # should fail with proba < 1e-26 + # scalar version + _, counts = hist([rand(rng, T) for i in 1:2000], bins) + @test minimum(counts) > 300 + end + end +end diff --git a/test/reflection.jl b/test/reflection.jl index d93e7affa686b..24962bc83491c 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -1,23 +1,22 @@ # code_native / code_llvm (issue #8239) - -# redirect stdout and stderr to avoid spam during tests. -oldout = STDOUT -olderr = STDERR -redirect_stdout() -redirect_stderr() - # It's hard to really test these, but just running them should be # sufficient to catch segfault bugs. -@test code_native(ismatch, (Regex, AbstractString)) == nothing -@test code_native(+, (Int, Int)) == nothing -@test code_native(+, (Array{Float32}, Array{Float32})) == nothing -@test code_llvm(ismatch, (Regex, AbstractString)) == nothing -@test code_llvm(+, (Int, Int)) == nothing -@test code_llvm(+, (Array{Float32}, Array{Float32})) == nothing +function test_code_reflection(freflect, f, types) + iob = IOBuffer() + freflect(iob, f, types) + str = takebuf_string(iob) + @test !isempty(str) +end + +println(STDERR, "The following 'Returned code...' warnings indicate normal behavior:") +test_code_reflection(code_native, ismatch, (Regex, AbstractString)) +test_code_reflection(code_native, +, (Int, Int)) +test_code_reflection(code_native, +, (Array{Float32}, Array{Float32})) -redirect_stdout(oldout) -redirect_stderr(olderr) +test_code_reflection(code_llvm, ismatch, (Regex, AbstractString)) +test_code_reflection(code_llvm, +, (Int, Int)) +test_code_reflection(code_llvm, +, (Array{Float32}, Array{Float32})) @test_throws Exception code_native(+, Int, Int) @test_throws Exception code_native(+, Array{Float32}, Array{Float32}) @@ -25,6 +24,45 @@ redirect_stderr(olderr) @test_throws Exception code_llvm(+, Int, Int) @test_throws Exception code_llvm(+, Array{Float32}, Array{Float32}) +# code_warntype +module WarnType +using Base.Test + +iob = IOBuffer() + +pos_stable(x) = x > 0 ? x : zero(x) +pos_unstable(x) = x > 0 ? x : 0 + +tag = Base.have_color ? Base.text_colors[:red] : "UNION" +code_warntype(iob, pos_unstable, (Float64,)) +str = takebuf_string(iob) +@test !isempty(search(str, tag)) +code_warntype(iob, pos_stable, (Float64,)) +str = takebuf_string(iob) +@test isempty(search(str, tag)) + +type Stable{T,N} + A::Array{T,N} +end +type Unstable{T} + A::Array{T} +end +Base.getindex(A::Stable, i) = A.A[i] +Base.getindex(A::Unstable, i) = A.A[i] + +tag = Base.have_color ? Base.text_colors[:red] : "ARRAY{FLOAT64,N}" +code_warntype(iob, getindex, (Unstable{Float64},Int)) +str = takebuf_string(iob) +@test !isempty(search(str, tag)) +code_warntype(iob, getindex, (Stable{Float64,2},Int)) +str = takebuf_string(iob) +@test isempty(search(str, tag)) +code_warntype(iob, getindex, (Stable{Float64},Int)) +str = takebuf_string(iob) +@test !isempty(search(str, tag)) + +end + # isbits @test !isbits(Array{Int}) diff --git a/test/repl.jl b/test/repl.jl index 3119109ede495..52ff4bf0a21be 100644 --- a/test/repl.jl +++ b/test/repl.jl @@ -169,6 +169,19 @@ begin @test buffercontents(LineEdit.buffer(s)) == "2 + 2" LineEdit.history_next(s, hp) + # Test that the same holds for prefix search + ps = LineEdit.state(s,interface.modes[5]) + LineEdit.history_prev_prefix(ps, hp, "") + @test ps.parent == repl_mode + @test LineEdit.input_string(ps) == "2 + 2" + LineEdit.history_prev_prefix(ps, hp, "") + @test ps.parent == shell_mode + @test LineEdit.input_string(ps) == "ls" + LineEdit.history_prev_prefix(ps, hp, "sh") + @test ps.parent == repl_mode + @test LineEdit.input_string(ps) == "shell" + LineEdit.history_next_prefix(ps, hp, "sh") + # Test that searching backwards puts you into the correct mode and # skips invalid modes. LineEdit.enter_search(s, histp, true) diff --git a/test/replcompletions.jl b/test/replcompletions.jl index 88d3cb329b447..aab94b650e69f 100644 --- a/test/replcompletions.jl +++ b/test/replcompletions.jl @@ -1,6 +1,13 @@ using Base.REPLCompletions module CompletionFoo + type Test_y + yy + end + type Test_x + xx :: Test_y + end + type_test = Test_x(Test_y(1)) module CompletionFoo2 end @@ -11,6 +18,19 @@ module CompletionFoo end end +function temp_pkg_dir(fn::Function) + # Used in tests below to setup and teardown a sandboxed package directory + const tmpdir = ENV["JULIA_PKGDIR"] = joinpath(tempdir(),randstring()) + @test !isdir(Pkg.dir()) + try + mkpath(Pkg.dir()) + @test isdir(Pkg.dir()) + fn() + finally + rm(tmpdir, recursive=true) + end +end + test_complete(s) = completions(s,endof(s)) test_scomplete(s) = shell_completions(s,endof(s)) test_latexcomplete(s) = latex_completions(s,endof(s))[2] @@ -54,6 +74,21 @@ c,r = test_complete(s) @test s[r] == "@f" @test !("foo" in c) +s = "Main.CompletionFoo.type_test.x" +c,r = test_complete(s) +@test "xx" in c +@test r == 30:30 +@test s[r] == "x" + +# To complete on a variable of a type, the type T of the variable +# must be a concrete type, hence Base.isstructtype(T) returns true, +# for the completion to succeed. That why `xx :: Test_y` of `Test_x`. +s = "Main.CompletionFoo.type_test.xx.y" +c,r = test_complete(s) +@test "yy" in c +@test r == 33:33 +@test s[r] == "y" + # issue #6333 s = "Base.return_types(getin" c,r = test_complete(s) @@ -93,38 +128,58 @@ c,r,res = test_complete(s) @test r == 7:12 @test length(c) == 1 +s = "\\a" +c, r, res = test_complete(s) +"\\alpha" in c +@test r == 1:2 +@test s[r] == "\\a" + # `cd("C:\U should not make the repl crash due to escaping see comment #9137 s = "cd(\"C:\\U" c,r,res = test_complete(s) -## Test completion of packages -#mkp(p) = ((@assert !isdir(p)); mkdir(p)) -#temp_pkg_dir() do -# mkp(Pkg.dir("MyAwesomePackage")) -# mkp(Pkg.dir("CompletionFooPackage")) -# -# s = "using MyAwesome" -# c,r = test_complete(s) -# @test "MyAwesomePackage" in c -# @test s[r] == "MyAwesome" -# -# s = "using Completion" -# c,r = test_complete(s) -# @test "CompletionFoo" in c #The module -# @test "CompletionFooPackage" in c #The package -# @test s[r] == "Completion" -# -# s = "using CompletionFoo.Completion" -# c,r = test_complete(s) -# @test "CompletionFoo2" in c -# @test s[r] == "Completion" -# -# rm(Pkg.dir("MyAwesomePackage")) -# rm(Pkg.dir("CompletionFooPackage")) -#end - -#This should not throw an error -c,r = test_scomplete("\$a") +# Test method completions +s = "max(" +c, r, res = test_complete(s) +@test !res +@test c[1] == string(start(methods(max))) +@test r == 1:3 +@test s[r] == "max" + +# Test completion in multi-line comments +s = "#=\n\\alpha" +c, r, res = test_complete(s) +@test c[1] == "α" +@test r == 4:9 +@test length(c) == 1 + +# Test that completion do not work in multi-line comments +s = "#=\nmax" +c, r, res = test_complete(s) +@test length(c) == 0 + +# Test completion of packages +mkp(p) = ((@assert !isdir(p)); mkdir(p)) +temp_pkg_dir() do + mkp(Pkg.dir("CompletionFooPackage")) + + s = "using Completion" + c,r = test_complete(s) + @test "CompletionFoo" in c #The module + @test "CompletionFooPackage" in c #The package + @test s[r] == "Completion" +end + +# Test $ in shell-mode +s = "cd \$(max" +c, r, res = test_scomplete(s) +@test "max" in c +@test r == 6:8 +@test s[r] == "max" + +# The return type is of importance, before #8995 it would return nothing +# which would raise an error in the repl code. +@test (UTF8String[], 0:-1, false) == test_scomplete("\$a") @unix_only begin #Assume that we can rely on the existence and accessibility of /tmp diff --git a/test/runtests.jl b/test/runtests.jl index 316080e746f61..d9154c168b5a5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -11,7 +11,7 @@ testnames = [ "sysinfo", "rounding", "ranges", "mod2pi", "euler", "show", "lineedit", "replcompletions", "repl", "test", "goto", "llvmcall", "grisu", "nullable", "meta", "profile", - "libgit2", "docs" + "libgit2", "docs", "base64" ] if isdir(joinpath(JULIA_HOME, Base.DOCDIR, "examples")) @@ -27,7 +27,7 @@ tests = (ARGS==["all"] || isempty(ARGS)) ? testnames : ARGS if "linalg" in tests # specifically selected case filter!(x -> x != "linalg", tests) - prepend!(tests, ["linalg1", "linalg2", "linalg3", "linalg4", "linalg/lapack", "linalg/triangular", "linalg/tridiag", "linalg/pinv", "linalg/cholmod", "linalg/umfpack"]) + prepend!(tests, ["linalg1", "linalg2", "linalg3", "linalg4", "linalg/lapack", "linalg/triangular", "linalg/tridiag", "linalg/pinv", "linalg/cholmod", "linalg/umfpack", "linalg/givens"]) end net_required_for = ["socket", "parallel"] diff --git a/test/show.jl b/test/show.jl index 049c452804b3f..a3ce295ba4da5 100644 --- a/test/show.jl +++ b/test/show.jl @@ -191,3 +191,12 @@ end" @test_repr "< :: T" @test_repr "S{< <: T}" @test_repr "+ + +" + +# issue #9474 +for s in ("(1::Int64 == 1::Int64)::Bool", "(1:2:3) + 4", "x = 1:2:3") + @test sprint(show, parse(s)) == ":("*s*")" +end + +# parametric type instantiation printing +immutable TParametricPrint{a}; end +@test sprint(show, :(TParametricPrint{false}())) == ":(TParametricPrint{false}())" diff --git a/test/sparse.jl b/test/sparse.jl index 5a2472d13c6d9..7cc0d2792d4c5 100644 --- a/test/sparse.jl +++ b/test/sparse.jl @@ -472,3 +472,6 @@ end # issue #8976 @test conj(sparse([1im])) == sparse(conj([1im])) @test conj!(sparse([1im])) == sparse(conj!([1im])) + +# issue #9525 +@test_throws BoundsError sparse([3], [5], 1.0, 3, 3) \ No newline at end of file diff --git a/ui/repl.c b/ui/repl.c index 04ac813e2330c..d9576e25f4127 100644 --- a/ui/repl.c +++ b/ui/repl.c @@ -72,6 +72,7 @@ static const char *opts = " --track-allocation={none|user|all}\n" " Count bytes allocated by each source line\n" " --check-bounds={yes|no} Emit bounds checks always or never (ignoring declarations)\n" + " --inline={yes|no} Control whether inlining is permitted (even for functions declared as @inline)\n" " -O, --optimize Run time-intensive code optimizations\n" " --int-literals={32|64} Select integer literal size independent of platform\n" " --dump-bitcode={yes|no} Dump bitcode for the system image (used with --build)\n" @@ -95,6 +96,7 @@ void parse_opts(int *argcp, char ***argvp) { "dump-bitcode", required_argument, 0, 302 }, { "compile", required_argument, 0, 303 }, { "depwarn", required_argument, 0, 304 }, + { "inline", required_argument, 0, 305 }, { 0, 0, 0, 0 } }; int c; @@ -198,6 +200,16 @@ void parse_opts(int *argcp, char ***argvp) exit(1); } break; + case 305: /* inline */ + if (!strcmp(optarg,"yes")) + jl_compileropts.can_inline = 1; + else if (!strcmp(optarg,"no")) + jl_compileropts.can_inline = 0; + else { + ios_printf(ios_stderr, "julia: invalid argument to --inline (%s)\n", optarg); + exit(1); + } + break; default: ios_printf(ios_stderr, "julia: unhandled option -- %c\n", c); ios_printf(ios_stderr, "This is a bug, please report it.\n");