As the maintainer of StructuredQueries.jl, I appreciate the recognition :) The JuliaStats community is indeed aiming for a more integrated ecosystem. It will take time, but I agree with you that our general direction is heartening.
"Lifting" in this context essentially refers to extending a function defined on certain domain of values, say X, to a domain X' which "includes" (air quotes because see below) all the values in X and some representation of a missing value from the domain X. The extended function should derive its behavior from the original function in some systematic way.
More concretely: suppose we have functionality `f` defined over a domain of objects of type `T` -- that is, we're given a method `f(x::T)`. In this case, the domain X is the set of all values of type `T`. The extended set X' is the set of all values of type `Nullable{T}`, where `Nullable{T}` is a specialized container type that can contain precisely zero or one values (an empty `Nullable{T}` object represents a missing value of type `T`, at least for our purposes). I quoted "includes" above because technically the domain of values of type `Nullable{T}` doesn't strictly include values of type `T` (the original domain X), but it includes a set of values that is "isomorphic" in some loose sense to this X. Lifting `f` over `Nullable{T}` arguments means systematically deriving some behavior for `f(x::Nullable{T})` from the original behavior `f(x::T)`. The standard semantics for this are to return `Nullable(f(x.value))` if `x` is null and return an empty `Nullable{U}` if `x` is null, where `U` depends somehow on `f` and `T`.
It's worth noting that the solution to lifting adopted in SQ does not automatically give lifted behavior to `f(x::Nullable{T})` when the latter is invoked outside of a querying macro.
Hi! I'm the author of the blog post and maintainer of the discussed package.
As CurtHagenlocher notes, in R functions can access passed expressions without evaluating them. So, even though the name `sepal_length` may not be bound to any object in the scope in which `select(sepal_length)` is called, one can use R's non-standard evaluation to process the expression `sepal_length` without trying to resolve the name.
Julia does not have non-standard evaluation, so `select(sepal_length)` necessarily attempts to resolve `sepal_length`, which is a problem if `sepal_length` is not a valid name. Using a macro to an extent emulates the effect of R's non-standard evaluation, at least when it comes to being able to name columns as arguments to manipulation verbs without having to symbolicate them or wrap them in quotes.
The advantages go beyond name resolution. One could resign oneself to symbolicating everywhere, i.e. writing `:sepal_length` to refer to the appropriate column. But then one starts to run into issues when one tries to handle expressions involving function calls. For instance, suppose you want to implement `filter` as an actual function. Well, you could ask users to invoke `filter(iris, :sepal_length > .5)`. This is fine so far as name resolution goes. But the argument `:sepal_length > .5` will throw a `MethodError` when evaluated, because there's no method for comparing a `Symbol` object to a `Float64` object. Using a macro-based regime allows us to access directly the AST representing `sepal_length > .5` and generate a lambda that mirrors the predicate's structure.
One of the main points of the post, which perhaps gets lost in the verbiage, is that, while we're using macros to allow for unqualified (i.e., un-symbolicated, un-stringed) mention of column names in the context of manipulation verb arguments, we can perform a number of other services (such as "automatic" lifting over `Nullable` arguments) and optimizations (such as having the resultant lambda take a tuple argument to avoid splatting, which is costly).
If a coin were flipped arbitrarily many times, and it landed on heads each time, and if we had no other information about the coin, a frequentist would say that the probability the coin lands on heads is one.
Now, you might protest and say, "But this is a fair coin that just happened to land on heads arbitrarily many times". But then you are relying on a prior definition of probability in order to justify your objection to the frequentist's claim, since presumably what you mean by "fair" is that the probability the coin lands on heads is 1/2.