{"action":"created","comment":{"url":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/comments/82328872","pull_request_review_id":3244853,"id":82328872,"diff_hunk":"@@ -0,0 +1,717 @@\n+---\n+layout: post\n+title:  Julia 0.5 Highlights\n+author: Stefan Karpinski\n+---\n+\n+Julia 0.5 is a pivotal release.\n+It introduces more transformative features than any release since the first official version.\n+Moreover, several of these features set the stage for even more to come in the [lead up to Julia 1.0](https://www.youtube.com/watch?v=5gXMpbY1kJY).\n+In this post, we'll go through some of the major changes in 0.5, including improvements to functional programming, comprehensions, generators, arrays, strings, and more.\n+\n+## Functions\n+\n+Julia has always had first-class functions that can be passed to and from other functions (i.e. [higher-order functions](https://en.wikipedia.org/wiki/Higher-order_function)) and full support for [lambdas](https://en.wikipedia.org/wiki/Anonymous_function).\n+Before this release, however, anonymous and higher-order functions came with a significant performance cost, and in a language that targets high-performance technical computing, that's a serious limitation.\n+So the Julia standard library and ecosystem have been rife with work-arounds to get the expressiveness of functional programming without the performance problems.\n+But the right solution, of course, is to make functional programming fast – ideally just as fast as the optimal hand-written version of your code would be.\n+In Julia 0.5, it is.\n+And that changes everything.\n+\n+This change is so important that there will be a separate blog post about it in the coming weeks, explaining how higher-order functions and lambdas have been made so efficient, as well as detailing the kinds of zero-cost abstractions these changes enable.\n+But for now, I'll just tease with a little timing comparison.\n+First, some definitions – they're the same in both 0.4 and 0.5:\n+\n+    v = rand(10^7);                   # 10 million random numbers\n+    double_it_vec(v) = 2v             # vectorized doubling of input\n+    double_it_map(v) = map(x->2x, v)  # map a lambda over input\n+\n+First, a timing comparison in Julia 0.4:\n+\n+    julia> VERSION\n+    v\"0.4.7\"\n+\n+    julia> mean([@elapsed(double_it_vec(v)) for _=1:100])\n+    0.024444888209999998\n+\n+    julia> mean([@elapsed(double_it_map(v)) for _=1:100])\n+    0.5515606454499999\n+\n+The functional version defined in terms of `map` is 22 times slower on 0.4 than the vectorized form using specialized generated code for maximal speed.\n+Second, the same comparison in Julia 0.5:\n+\n+    julia> VERSION\n+    v\"0.5.0\"\n+\n+    julia> mean([@elapsed(double_it_vec(v)) for _=1:100])\n+    0.024549842180000003\n+\n+    julia> mean([@elapsed(double_it_map(v)) for _=1:100])\n+    0.023871925960000002\n+\n+The version defined in terms of `map` is as fast as the vectorized method in 0.5.\n+In this case, writing `2v` happens to be more convenient than writing `map(x->2x, v)` – and, of course, you can keep using vectorized forms when they're convenient – but there are many cases where functional constructs are more general, clearer, and more convenient.\n+Now they're also fast.\n+\n+### Ambiguous methods\n+\n+One design decision that any multiple dispatch language must make is how to handle dispatch ambiguities: cases where none of the methods applicable to a given set of arguments is more specific than the rest.\n+Suppose, for example, that a generic function, `f`, has the following methods:\n+\n+    f(a::Int, b::Real) = 1\n+    f(a::Real, b::Int) = 2\n+\n+In Julia 0.4 and earlier, the second method definition causes an ambiguity warning:\n+\n+    WARNING: New definition\n+        f(Real, Int64) at none:1\n+    is ambiguous with:\n+        f(Int64, Real) at none:1.\n+    To fix, define\n+        f(Int64, Int64)\n+    before the new definition.\n+\n+This warning is clear and gets right to the point: the case `f(a,b)` where `a` and `b` are of type `Int` (aka `Int64` on 64-bit systems) is ambiguous.\n+Evaluating `f(3,4)` calls the first method of `f` – but this behavior is undefined.\n+Giving a warning whenever methods *could* be ambiguous is a fairly conservative choice: it urges people to define a method covering the ambiguous intersection before even defining the methods that overlap.\n+When we decided to give warnings for potentially ambiguous methods, we hoped that people would avoid ambiguities and all would be well in the world.\n+\n+Warning about method ambiguities turns out to be both too strict and too lenient.\n+It's far too easy for ambiguities to arise when shared generic functions serve as extension points across unrelated packages.\n+When many packages extend the same generic functions, it's common for the methods added to have some ambiguous overlap.\n+This happens even when each package has no ambiguities on its own.\n+Worse still, slight changes to one package can introduce ambiguities elsewhere, resulting in the least fun game of [whack-a-mole](https://en.wikipedia.org/wiki/Whac-A-Mole) ever.\n+At the same time, the fact that ambiguities *only* cause warnings means that people learn to ignore them, which is annoying at best, and dangerous at worst: it's far too easy for a real problem to be hidden by a barrage of insignificant ambiguity warnings.\n+In particular, on 0.4 and earlier if an ambiguous method is actually called, no error occurs.\n+Instead, one of the possible methods is called, based on the order in which methods were defined – which is essentially arbitrary when they come from different packages.\n+Usually the method works – it does apply, after all – but this is clearly not the right thing to do.\n+\n+The solution is simple: in Julia 0.5 the existence of potential ambiguities is fine, but actually calling an ambiguous method is an immediate error.\n+The above method definitions for `f`, which previously triggered a warning, are now silent, but *calling* `f` with two `Int` arguments is a method dispatch error:\n+\n+    julia> f(3,4)\n+    ERROR: MethodError: f(::Int64, ::Int64) is ambiguous. Candidates:\n+      f(a::Real, b::Int64) at REPL[2]:1\n+      f(a::Int64, b::Real) at REPL[1]:1\n+     in eval(::Module, ::Any) at ./boot.jl:231\n+     in macro expansion at ./REPL.jl:92 [inlined]\n+     in (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:46\n+\n+This improves the experience of using the Julia package ecosystem considerably, while also making Julia safer and more reliable.\n+No more torrent of insignificant ambiguity warnings.\n+No more playing ambiguity whack-a-mole when someone else refactors their code and accidentally introduces ambiguities in yours.\n+No more risk that a method call could be silently broken because of warnings that we've all learned to ignore.\n+\n+### Return type annotations\n+\n+A long-requested feature has been the ability to annotate method definitions with an explicit return type.\n+This aids the clarity of code, serves as self-documentation, helps the compiler reason about code, and ensures that return types are what programmers intend them to be.\n+In 0.5, you can annotate method definitions with a return type like so:\n+\n+    function clip{T<:Real}(x::T, lo::Real, hi::Real)::T\n+        if x < lo\n+            return lo\n+        elseif x > hi\n+            return hi\n+        else\n+            return x\n+        end\n+    end\n+\n+This annotation on `clip` has the effect of inserting implicit calls to `x->convert(T, x)` at each return point of the method.\n+It has no effect on any other method of `clip`, only the one where the annotation occurs.\n+In this case, the annotation ensures that this method always returns a value of the same type as `x`, regardless of the types of `lo` and `hi`:\n+\n+    julia> clip(0.5, 1, 2)\n+    1.0\n+\n+    julia> clip(1.5, 1, 2)\n+    1.5\n+\n+    julia> clip(2.5, 1, 2)\n+    2.0\n+\n+You'll note that the annotated return type here is `T`, which is a type parameter of the `clip` method.\n+Not only is that allowed, but the return type can be an arbitrary expression of argument values, type parameters, and values from outer scopes.\n+For example, here is a variation that promotes its arguments:\n+\n+    function clip2(x::Real, lo::Real, hi::Real)::promote_type(typeof(x), typeof(lo), typeof(hi))\n+        if x < lo\n+            return lo\n+        elseif x > hi\n+            return hi\n+        else\n+            return x\n+        end\n+    end\n+\n+    julia> clip2(2, 1, 3)\n+    2\n+\n+    julia> clip2(2, 1, 13//5)\n+    2//1\n+\n+    julia> clip2(2.5, 1, 13//5)\n+    2.5\n+\n+Return type annotations are a fairly simple syntactic transformation, but they make it easier to write methods with consistent and predictable return types.\n+If different branches of your code can lead to slightly different types, the fix is now as simple as putting a single type annotation on the entire method.\n+\n+### Vectorized function calls\n+\n+Julia 0.5 introduces the syntax `f.(A1, A2, ...)` for vectorized function calls.\n+This syntax translates to `broadcast(f, A1, A2, ...)`, where `broadcast` is a higher-order function (introduced in 0.2), which generically implements the kind of broadcasting behavior found in Julia's \"dotted operators\" such as `.+`, `.-`, `.*`, and `./`.\n+Since higher-order functions are now efficient, writing `broadcast(f,v,w)` and `f.(v,w)` are both about as fast as loops specialized for the operation `f` and the shapes of `v` and `w`.\n+This syntax lets you vectorize your scalar functions the way built-in vectorized functions like `log`, `exp`, and `atan2` work.\n+In fact, in the future, this syntax may replace the pre-vectorized methods of functions like `exp` and `log`, so that users will write `exp.(v)` to exponentiate a vector of values.\n+This may seem a little bit uglier, but it's more consistent than choosing an essentially arbitrarily set of functions to pre-vectorize.\n+But beyond that, as I'll explain below, this approach can have major performance benefits as well.\n+\n+To give a more concrete sense of what this syntax can be used for, consider the `clip` function defined previously for real arguments.\n+This scalar function can be applied to vectors using vectorized call syntax without any further method definitions:\n+\n+    julia> v = randn(10)\n+    10-element Array{Float64,1}:\n+     -0.868996\n+      1.79301\n+     -0.309632\n+      1.16802\n+     -1.57178\n+     -0.223385\n+     -0.608423\n+     -1.54862\n+     -1.33672\n+      0.864448\n+\n+    julia> clip.(v, -1, 1)\n+    10-element Array{Float64,1}:\n+     -0.868996\n+      1.0\n+     -0.309632\n+      1.0\n+     -1.0\n+     -0.223385\n+     -0.608423\n+     -1.0\n+     -1.0\n+      0.864448\n+\n+The second and third argument don't need to be scalars – as with dotted operators, they can be vectors as well, and the `clip` operation will be applied to each corresponding triple of values:\n+\n+    julia> clip.(v, repmat([-1,0.5],5), repmat([-0.5,1],5))\n+    10-element Array{Float64,1}:\n+     -0.868996\n+      1.0\n+     -0.5\n+      1.0\n+     -1.0\n+      0.5\n+     -0.608423\n+      0.5\n+     -1.0\n+      0.864448\n+\n+From this example, it may be unclear why this operation is called \"`broadcast`\".\n+The function gets its name from the following behavior:\n+wherever one of its arguments has a singleton dimension, it \"broadcasts\" that value along the corresponding dimension of the other arguments when applying the operator.\n+This behavior allows dotted operations to easily do handy tricks like quickly mean-centering the columns of a matrix:\n+\n+    julia> A = rand(3,4);\n+\n+    julia> B = A .- mean(A,1)\n+    3×4 Array{Float64,2}:\n+      0.343976   0.427378  -0.503356  -0.00448691\n+     -0.210096  -0.531489   0.168928  -0.128212\n+     -0.13388    0.104111   0.334428   0.132699\n+\n+    julia> mean(B,1)\n+    1×4 Array{Float64,2}:\n+     0.0  0.0  0.0  0.0\n+\n+The matrix `A` is 3×4 and `mean(A,1)` is 1×4 so the `.-` operator broadcasts each column's mean along the values of the column in A, subtracting that mean from each element.\n+Combining this broadcasting behavior with vectorized call syntax let's us write some fairly fancy custom array operations very concisely:\n+\n+    julia> clip.(B, [-0.3, -0.2, -0.1], [0.4, 0.3, 0.2, 0.1]')\n+    3×4 Array{Float64,2}:\n+      0.343976   0.3       -0.3       -0.00448691\n+     -0.2       -0.2        0.168928  -0.128212\n+     -0.1        0.104111   0.2        0.1\n+\n+This clips each element of `B` with its own specific `(hi,lo)` pair, as in this matrix:\n+\n+    julia> [(lo,hi) for lo=[-0.3, -0.2, -0.1], hi=[0.4, 0.3, 0.2, 0.1]]\n+    3×4 Array{Tuple{Float64,Float64},2}:\n+     (-0.3,0.4)  (-0.3,0.3)  (-0.3,0.2)  (-0.3,0.1)\n+     (-0.2,0.4)  (-0.2,0.3)  (-0.2,0.2)  (-0.2,0.1)\n+     (-0.1,0.4)  (-0.1,0.3)  (-0.1,0.2)  (-0.1,0.1)\n+\n+Except that with the vectorized call syntax, the matrix of pairs never has to be constructed, nor does the messy code to apply `clip` to each element of `B` together with the corresponding `lo` and `hi` need to be written.\n+When `B` is larger than it is in this toy example, avoiding constructing a matrix of `(lo,hi)` pairs can be a big efficiency win.\n+\n+There is a bit more to the vectorized calls syntax story.\n+It's common to write expressions applying multiple vectorized functions to some arrays.\n+For example, one might write something like:\n+\n+    atan2(cos(X), sin(Y))\n+\n+Currently, this allocates two temporary intermediate arrays – one to store `cos(X)` and one for `sin(Y)`.\n+If we use vectorized function call syntax, however, these calls are syntactically fused into a *single* call to `broadcast` with an anonymous function.\n+In other words, `atan2.(cos.(X), sin.(Y))` becomes\n+\n+    broadcast((x, y)->atan2(cos(x), sin(y)), X, Y)\n+\n+This computation avoids allocating any intermediate arrays and performs the entire vectorized computation all at once into the result array.\n+We can see this difference in allocation when we benchmark these expressions:\n+\n+    julia> using BenchmarkTools\n+\n+    julia> X, Y = rand(1000,1000), rand(1000,1000);\n+\n+    julia> @benchmark atan2(cos(X), sin(Y))\n+    BenchmarkTools.Trial:\n+      memory estimate:  22.89 mb\n+      allocs estimate:  13\n+      minimum time:     54.09 ms (1.32% GC)\n+      median time:      55.82 ms (4.30% GC)\n+      mean time:        55.89 ms (4.25% GC)\n+      maximum time:     56.95 ms (4.36% GC)\n+\n+    julia> @benchmark atan2.(cos.(X), sin.(Y))\n+    BenchmarkTools.Trial:\n+      memory estimate:  7.63 mb\n+      allocs estimate:  38\n+      minimum time:     51.83 ms (0.00% GC)\n+      median time:      52.18 ms (0.00% GC)\n+      mean time:        52.94 ms (1.48% GC)\n+      maximum time:     57.91 ms (4.17% GC)\n+\n+    julia> 22.89/7.63\n+    3.0\n+\n+I'm using the [`BenchmarkTools`](https://github.com/JuliaCI/BenchmarkTools.jl) package here instead of hand-rolled timing loops. `BenchmarkTools` has been carefully designed to avoid many of the common pitfalls of benchmarking code and to provide sound statistical estimates of how much time and memory your code uses.\n+For the sake of brevity, I'm omitting some of the less relevant output from `@benchmark`.\n+As you can see, the speed gain from fused broadcasting is marginal, but allocations are reduced by a factor of 3 as predicted – only the output array is allocated, no temporaries are.\n+But the real reduction in allocation comes when we use the new `.=` operator to also do vectorized assignment:\n+\n+    julia> Z = zeros(X);\n+\n+    julia> @benchmark Z .= atan2.(cos.(X), sin.(Y))\n+    BenchmarkTools.Trial:\n+      memory estimate:  96.00 bytes\n+      allocs estimate:  3\n+      minimum time:     50.76 ms (0.00% GC)\n+      median time:      50.98 ms (0.00% GC)\n+      mean time:        51.08 ms (0.00% GC)\n+      maximum time:     52.23 ms (0.00% GC)\n+\n+With in-place vectorized assignment, we can fill the pre-allocated array, `Z`, without doing any allocation (the 96 bytes is an artifact).\n+\n+The last major missing piece of vectorized call syntax is that in the future dotted operators will cease to be their own independent operators and simply become the vectorized form of the corresponding scalar operator.\n+In other words, instead of `.+` being a function as it is now, with it's own potentially unrelated behavior independent of `+`, it will simply be the vectorized form of `+`.\n+Thus, in the next version of Julia, when you write `A .+ B` it will mean `broadcast(+, A, B)`.\n+Moreover, this will participate in the same syntax-level fusion as other vectorized calls, so expressions like `exp.(log.(X) .+ log.(Y))` will translate into:\n+\n+    broadcast((x, y)->exp(log(x) + log(y)), X, Y)\n+\n+This change will complete the transition of Julia to using generalized vectorized function application with syntax-level loop fusion, which will make the story for writing allocation-free array code much stronger.\n+\n+## Comprehensions\n+\n+Julia's array comprehensions have always supported some advanced features such as iterating with several variables to produce multidimensional arrays.\n+This release rounds out the functionality of comprehensions with two additional features: nested generation with multiple `for` clauses, and filtering with a trailing `if` clause.\n+To demonstrate these features, consider making a dollar (100¢) using quarters (25¢), dimes (10¢), nickels (5¢) and pennies (1¢).\n+We can generate an array of tuples of total values in each kind of coin by using a comprehension with nested `for` clauses:\n+\n+    julia> change = [(q,d,n,p) for q=0:25:100 for d=0:10:100-q for n=0:5:100-q-d for p=100-q-d-n]\n+    242-element Array{NTuple{4,Int64},1}:\n+     (0,0,0,100)\n+     (0,0,5,95)\n+     (0,0,10,90)\n+     (0,0,15,85)\n+     (0,0,20,80)\n+     (0,0,25,75)\n+     ⋮\n+     (75,10,5,10)\n+     (75,10,10,5)\n+     (75,10,15,0)\n+     (75,20,0,5)\n+     (75,20,5,0)\n+     (100,0,0,0)\n+\n+There are a few notable differences from the multidimensional array syntax:\n+\n+- Each iteration is a new `for` clause, rather than a single compound iteration separated by commas.\n+- Each successive `for` clause *can* refer to variables from the previous clauses.\n+- The result is a single flat vector regardless of how many `for` clauses there are.\n+\n+The tuple `(q,d,n,p)` in the comprehension body is a breakdown of monetary value into quarters, dimes, nickels and pennies.\n+Note that the iteration range for `p` isn't a range at all, it's a single value, `100-q-d-n`, the unique number guaranteeing that each tuple adds up to a dollar.\n+(This relies on the fact that a number behaves like an immutable zero-dimensional container, holding only itself, a behavior which is sometimes convenient but which has been the subject of significant debate.\n+As of 0.5 it still works.)\n+We can verify that each tuple adds up to 100 using a comprehension to make an array of the sums of each tuple and passing that array to the `extrema` function, to find the minimum and maximum over all sums:\n+\n+    julia> extrema([sum(t) for t in change])\n+    (100,100)\n+\n+Since the minimum and maximum are both 100, the sums must all be exactly 100.\n+So, we know there are 242 ways to make a dollar with common coins.\n+But suppose we want to ensure that the value in pennies is less than the value in nickels, and so forth.\n+By adding a filter clause, we can do this easily too:\n+\n+    julia> [(q,d,n,p) for q=0:25:100 for d=0:10:100-q for n=0:5:100-q-d for p=100-q-d-n if p < n < d < q]\n+    4-element Array{NTuple{4,Int64},1}:\n+     (50,30,15,5)\n+     (50,30,20,0)\n+     (50,40,10,0)\n+     (75,20,5,0)\n+\n+The only difference here is the `if p < n < d < q` clause at the end of the comprehension, which has the effect that the result only contains cases where the predicate holds true.\n+There are exactly four ways make a dollar with strictly increasing value from pennies to nickels to dimes to quarters.\n+\n+Nested and filtered comprehensions aren't earth-shattering features – everything you can do with them can be done in a variety of other ways – but they are expressive and convenient, found in other languages, and they allow you to try more things with your data quickly and easily, with less tedious refactoring.\n+\n+## Generators\n+\n+In the previous section we used an array comprehension to take the sum of each tuple, save the sums as an array, and then pass that array of sums to the `extrema` function to find the largest and smallest sum (they should all be 100):\n+\n+    julia> extrema([sum(t) for t in change])\n+    (100,100)\n+\n+But allocating an array of sums here is unnecessary: the minimum and maximum can be computed over streamed data, simply by keeping the largest and smallest values seen so far.\n+In other words, this calculation could be expressed with constant memory overhead by interleaving the production of values with computation of extreme values.\n+In Julia 0.4, the most straightforward way to express such an interleaved computation was to manually perform the interleaving (aka \"cut and paste\").\n+In 0.5, if you simply omit the square brackets around an array comprehension, you get a *generator expression*, which instead of producing an array of values, can be iterated over, yielding one value at a time.\n+Since `extrema` works with arbitrary iterable objects – including generators – expressing an interleaved calculation using constant memory is now as simple as deleting `[` and `]`:\n+\n+    julia> extrema(sum(t) for t in change)\n+    (100,100)\n+\n+This avoids allocating a temporary array of sums entirely, instead computing the next tuple sum only when the `extrema` function is ready to accept a new value.\n+In this case, the allocation saved is trivial, but it transforms this code's memory overhead from *O(n)* in the number of samples to *O(1)*.\n+It's not hard to imagine situations where such a reduction in asymptotic memory usage is crucial.\n+The similar syntax between array comprehensions and generator expressions makes it trivial to move back and forth between the two styles of computation as needed.\n+\n+### Initializing collections\n+\n+The new generator syntax dovetails particularly nicely with Julia's convention for constructing collections – to make a new collection, you call the constructor with a single iterable argument, which yields the values you want in the new collection.\n+In its simplest form, this looks something like:\n+\n+    julia> IntSet([1, 4, 9, 16, 25, 36, 49, 64])\n+    IntSet([1, 4, 9, 16, 25, 36, 49, 64])\n+\n+In this input expression, an array of integers is passed to the `IntSet` constructor to create an object representing that set, which in this case happen to be small squares.\n+Once constructed, the `IntSet` object no longer refers to the original array of integers.\n+Instead, it uses a bitmask to efficiently store and operate on sets.\n+It displays itself as you would construct it from an array of integers, but that's merely for convenience – there's no actual array anymore.\n+\n+Now, I'm a human (no blogbots here) and I find typing out even short sequences of perfect squares tedious and error prone – despite a math degree, I'm awful at arithmetic.\n+It would be much easier to generate the values to go in this `IntSet` with an array comprehension:\n+\n+    julia> IntSet([k^2 for k = 1:8])\n+    IntSet([1, 4, 9, 16, 25, 36, 49, 64])\n+\n+This comprehension produces the same array of integers that I typed above.\n+Creating an array object is unnecessary, though – it would be even better to generate the desired squares just as they are inserted into the `IntSet` being constructed.\n+Which, of course, is precisely what generator expressions allow:\n+\n+    julia> IntSet(k^2 for k = 1:8) # no temporary array!\n+    IntSet([1, 4, 9, 16, 25, 36, 49, 64])\n+\n+More concise, just as clear, and (as we're about to see) faster – let's benchmark these two constructions:\n+\n+    julia> using BenchmarkTools\n+\n+    julia> @benchmark IntSet([k^2 for k = 1:8])\n+    BenchmarkTools.Trial:\n+      memory estimate:  320.00 bytes\n+      allocs estimate:  5\n+      minimum time:     163.00 ns (0.00% GC)\n+      median time:      199.00 ns (0.00% GC)\n+      mean time:        245.18 ns (12.95% GC)\n+      maximum time:     5.36 μs (92.47% GC)\n+\n+    julia> @benchmark IntSet(k^2 for k = 1:8)\n+    BenchmarkTools.Trial:\n+      memory estimate:  160.00 bytes\n+      allocs estimate:  3\n+      minimum time:     114.00 ns (0.00% GC)\n+      median time:      139.00 ns (0.00% GC)\n+      mean time:        165.74 ns (11.48% GC)\n+      maximum time:     4.82 μs (93.20% GC)\n+\n+As you can see here, the version with an array comprehension uses twice as much memory and is 50% slower than the one that uses a generator expression.\n+\n+#### Constructing dictionaries\n+\n+Generators can be used to construct dictionaries too, and this use case deserves some special attention since it completes a multi-release process of putting user-defined dictionary types on an equal footing with the built-in `Dict` type.\n+In Julia 0.3, the `=>` operator only existed as part of syntax for constructing `Dict` objects – e.g. `[k₁ => v₁, k₂ => v₂]` or `[k(i) => v(i) for i = c]`.\n+This design was based on other dynamic languages where dictionaries are among a small set of built-in types, that have special syntax and are deeply integrated into the system.\n+As Julia's ecosystem has matured, however, it has become apparent that Julia is actually more like Java or C++ in this respect than it is like Python or Lua: the `Dict` type isn't that special – it happens to be defined in the standard library, but is otherwise quite ordinary.\n+Many programs use other dictionary implementations: for example, the tree-based `SortedDict` type, which sorts values by key; or `OrderedDict`, which maintains keys in the order they are inserted.\n+Having special syntax only for `Dict` makes using other dictionary implementations problematic.\n+In 0.3, there was no good syntax for constructing values of these dictionaries – the best one could do was to invoke a constructor with an array of two-tuples:\n+\n+    SortedDict([(k₁, v₁), (k₂, v₂)])        # fixed-size dictionaries\n+    SortedDict([(k(i), v(i)) for i in c])   # dictionary comprehensions\n+\n+Not only are these constructions inconvenient and ugly, they're also inefficient since they create temporary heap-allocated arrays of heap-allocated tuples of key-value pairs.\n+In Julia 0.5, with much relief, we can now instead write:\n+\n+    SortedDict(k₁ => v₁, k₂ => v₂)          # fixed-size dictionaries, since 0.4\n+    SortedDict(k(i) => v(i) for i = c)      # dictionary comprehensions, since 0.5\n+\n+This syntax combines two orthogonal features introduced in 0.4 and 0.5, respectively: `k => v` as standalone syntax for a `Pair` object and generator expressions.\n+The `Dict` type is now constructed in exactly the same way:\n+\n+    julia> Dict(\"foo\" => 1, \"bar\" => 2)\n+    Dict{String,Int64} with 2 entries:\n+      \"bar\" => 2\n+      \"foo\" => 1\n+\n+    julia> Dict(\"*\"^k => k for k = 1:10)\n+    Dict{String,Int64} with 10 entries:\n+      \"**********\" => 10\n+      \"***\"        => 3\n+      \"*******\"    => 7\n+      \"********\"   => 8\n+      \"*\"          => 1\n+      \"**\"         => 2\n+      \"****\"       => 4\n+      \"*********\"  => 9\n+      \"*****\"      => 5\n+      \"******\"     => 6\n+\n+This generalization makes the syntax for constructing a `Dict` slightly longer, but we feel that the increased consistency, ability to change dictionary implementations with a simple search-and-replace, and putting user-defined dictionary-like types on the same level as the standard `Dict` make this change well worthwhile.\n+\n+## Arrays\n+\n+The 0.5 release was originally intended to include a large number of disruptive array changes, collectively dubbed \"Arraymageddon\".\n+After much discussion, experimentation and benchmarking, this set of breaking changes was significantly reduced for a variety of reasons:\n+\n+- Some changes were deemed not to be good ideas after all;\n+- Others were of unclear benefit, so it was decided to reconsider them in the future once more evidence became available one way or the other;\n+- A few didn't get implemented due to lack of developer time, including some cases where everyone agrees there's a problem but no complete design for a solution.\n+\n+Although most of the breaking changes didn't happen in 0.5, in a less obvious way, this was a major release for Julia's array infrastructure.\n+The code to implement the various complex polymorphic indexing operations for generic arrays and array-like structures was majorly refactored, and in the process it shrank by 40% while becoming more complete, more general, and faster.\n+You can read more about the very cool things you can do with array-like types in 0.5 in an excellent pair of blog posts published here earlier in the year on [multidimensional iteration tools](/blog/2016/02/iteration) and [generalizing abstract arrays](/blog/2016/03/arrays-iteration).\n+\n+### Dimension sum slices\n+\n+The most significant breaking change in the 0.5 cycle affects multidimensional array slicing.\n+To explain it we'll need a little terminology.\n+A *singleton dimension* of a multidimensional array is a dimension whose size is 1.\n+For example, a 5x1 matrix has a trailing singleton dimension and may be called a \"column matrix\", and a 1x5 matrix has a leading singleton dimension and may be called a \"row matrix\".\n+A *scalar slice* refers to a dimension in a multidimensional slice expression where the index is a scalar integer (considered to be zero-dimensional), rather than a 1-dimensional range or vector, or some higher-dimensional collection of indices.\n+For example, in `A[1,:]` the first slice is scalar, the second is not; in `A[:,2]` the second slice is scalar, the second is not; in `A[3,4]` both slices are scalar.","path":"blog/_posts/2016-10-06-julia-0.5-highlights.md","position":506,"original_position":506,"commit_id":"b4ee121bcee82ae54399285eb17752af351f81cb","original_commit_id":"b4ee121bcee82ae54399285eb17752af351f81cb","user":{"login":"Ismael-VC","id":4594825,"avatar_url":"https://avatars.githubusercontent.com/u/4594825?v=3","gravatar_id":"","url":"https://api.github.com/users/Ismael-VC","html_url":"https://github.com/Ismael-VC","followers_url":"https://api.github.com/users/Ismael-VC/followers","following_url":"https://api.github.com/users/Ismael-VC/following{/other_user}","gists_url":"https://api.github.com/users/Ismael-VC/gists{/gist_id}","starred_url":"https://api.github.com/users/Ismael-VC/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Ismael-VC/subscriptions","organizations_url":"https://api.github.com/users/Ismael-VC/orgs","repos_url":"https://api.github.com/users/Ismael-VC/repos","events_url":"https://api.github.com/users/Ismael-VC/events{/privacy}","received_events_url":"https://api.github.com/users/Ismael-VC/received_events","type":"User","site_admin":false},"body":"> in `A[:,2]` the second slice is scalar, the second is not;\r\n\r\nShould be *in `A[:,2]` the second slice is scalar, the first is not;*.","created_at":"2016-10-07T04:53:11Z","updated_at":"2016-10-07T04:53:11Z","html_url":"https://github.com/JuliaLang/julialang.github.com/pull/437#discussion_r82328872","pull_request_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/437","_links":{"self":{"href":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/comments/82328872"},"html":{"href":"https://github.com/JuliaLang/julialang.github.com/pull/437#discussion_r82328872"},"pull_request":{"href":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/437"}}},"pull_request":{"url":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/437","id":88318518,"html_url":"https://github.com/JuliaLang/julialang.github.com/pull/437","diff_url":"https://github.com/JuliaLang/julialang.github.com/pull/437.diff","patch_url":"https://github.com/JuliaLang/julialang.github.com/pull/437.patch","issue_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues/437","number":437,"state":"open","locked":false,"title":"Julia 0.5 highlights blog post","user":{"login":"StefanKarpinski","id":153596,"avatar_url":"https://avatars.githubusercontent.com/u/153596?v=3","gravatar_id":"","url":"https://api.github.com/users/StefanKarpinski","html_url":"https://github.com/StefanKarpinski","followers_url":"https://api.github.com/users/StefanKarpinski/followers","following_url":"https://api.github.com/users/StefanKarpinski/following{/other_user}","gists_url":"https://api.github.com/users/StefanKarpinski/gists{/gist_id}","starred_url":"https://api.github.com/users/StefanKarpinski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/StefanKarpinski/subscriptions","organizations_url":"https://api.github.com/users/StefanKarpinski/orgs","repos_url":"https://api.github.com/users/StefanKarpinski/repos","events_url":"https://api.github.com/users/StefanKarpinski/events{/privacy}","received_events_url":"https://api.github.com/users/StefanKarpinski/received_events","type":"User","site_admin":false},"body":"Please don't post to news outlets yet.","created_at":"2016-10-06T18:44:42Z","updated_at":"2016-10-07T04:53:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e38b906e4c99c74ba20e92dde41891c3aad71949","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/437/commits","review_comments_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/437/comments","review_comment_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/comments{/number}","comments_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues/437/comments","statuses_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/statuses/b4ee121bcee82ae54399285eb17752af351f81cb","head":{"label":"JuliaLang:sk/0.5","ref":"sk/0.5","sha":"b4ee121bcee82ae54399285eb17752af351f81cb","user":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"repo":{"id":2885268,"name":"julialang.github.com","full_name":"JuliaLang/julialang.github.com","owner":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/JuliaLang/julialang.github.com","description":"Julia Project web site.","fork":false,"url":"https://api.github.com/repos/JuliaLang/julialang.github.com","forks_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/forks","keys_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/teams","hooks_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/hooks","issue_events_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues/events{/number}","events_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/events","assignees_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/assignees{/user}","branches_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/branches{/branch}","tags_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/tags","blobs_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/refs{/sha}","trees_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/statuses/{sha}","languages_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/languages","stargazers_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/stargazers","contributors_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/contributors","subscribers_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/subscribers","subscription_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/subscription","commits_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/commits{/sha}","git_commits_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/commits{/sha}","comments_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/comments{/number}","issue_comment_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues/comments{/number}","contents_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/contents/{+path}","compare_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/merges","archive_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/downloads","issues_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues{/number}","pulls_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls{/number}","milestones_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/milestones{/number}","notifications_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/labels{/name}","releases_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/releases{/id}","deployments_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/deployments","created_at":"2011-11-30T18:22:15Z","updated_at":"2016-10-03T00:52:25Z","pushed_at":"2016-10-07T03:37:27Z","git_url":"git://github.com/JuliaLang/julialang.github.com.git","ssh_url":"git@github.com:JuliaLang/julialang.github.com.git","clone_url":"https://github.com/JuliaLang/julialang.github.com.git","svn_url":"https://github.com/JuliaLang/julialang.github.com","homepage":"http://julialang.org/","size":9690,"stargazers_count":75,"watchers_count":75,"language":"TeX","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":149,"mirror_url":null,"open_issues_count":16,"forks":149,"open_issues":16,"watchers":75,"default_branch":"master"}},"base":{"label":"JuliaLang:master","ref":"master","sha":"90729b8f578629ca8f4603091fab27359ccf7f3a","user":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"repo":{"id":2885268,"name":"julialang.github.com","full_name":"JuliaLang/julialang.github.com","owner":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/JuliaLang/julialang.github.com","description":"Julia Project web site.","fork":false,"url":"https://api.github.com/repos/JuliaLang/julialang.github.com","forks_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/forks","keys_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/teams","hooks_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/hooks","issue_events_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues/events{/number}","events_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/events","assignees_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/assignees{/user}","branches_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/branches{/branch}","tags_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/tags","blobs_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/refs{/sha}","trees_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/statuses/{sha}","languages_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/languages","stargazers_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/stargazers","contributors_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/contributors","subscribers_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/subscribers","subscription_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/subscription","commits_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/commits{/sha}","git_commits_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/git/commits{/sha}","comments_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/comments{/number}","issue_comment_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues/comments{/number}","contents_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/contents/{+path}","compare_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/merges","archive_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/downloads","issues_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues{/number}","pulls_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls{/number}","milestones_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/milestones{/number}","notifications_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/labels{/name}","releases_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/releases{/id}","deployments_url":"https://api.github.com/repos/JuliaLang/julialang.github.com/deployments","created_at":"2011-11-30T18:22:15Z","updated_at":"2016-10-03T00:52:25Z","pushed_at":"2016-10-07T03:37:27Z","git_url":"git://github.com/JuliaLang/julialang.github.com.git","ssh_url":"git@github.com:JuliaLang/julialang.github.com.git","clone_url":"https://github.com/JuliaLang/julialang.github.com.git","svn_url":"https://github.com/JuliaLang/julialang.github.com","homepage":"http://julialang.org/","size":9690,"stargazers_count":75,"watchers_count":75,"language":"TeX","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":149,"mirror_url":null,"open_issues_count":16,"forks":149,"open_issues":16,"watchers":75,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/437"},"html":{"href":"https://github.com/JuliaLang/julialang.github.com/pull/437"},"issue":{"href":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues/437"},"comments":{"href":"https://api.github.com/repos/JuliaLang/julialang.github.com/issues/437/comments"},"review_comments":{"href":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/437/comments"},"review_comment":{"href":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/JuliaLang/julialang.github.com/pulls/437/commits"},"statuses":{"href":"https://api.github.com/repos/JuliaLang/julialang.github.com/statuses/b4ee121bcee82ae54399285eb17752af351f81cb"}}}}
{"actor":{"display_login":"Ismael-VC"}}