Can't override method

I tried to pirate this method so it doesn’t throw but it is ignored and throws an error. What is wrong?

Julia 1.7.1, PrettyTables master

[08abe8d2] PrettyTables v1.3.1 `https://github.com/ronisbr/PrettyTables.jl.git#master
using PrettyTables

# Pirate this function to allow arbitrary alignment specifiers.
function PrettyTables._latex_alignment(s::Symbol)
    if (s == :l) || (s == :L)
        return "l"
    elseif (s == :c) || (s == :C)
        return "c"
    elseif (s == :r) || (s == :R)
        return "r"
    else
        # Allow arbitrary alignments.
        return String(s)
    end
end

function maketable(d)
    pretty_table(d; tf=LatexTableFormat(), alignment=[:r,Symbol("d{5.5}")])
end

maketable((;a=[1,2,3], b=[10.1,20.2,30.3]))

#= 
ERROR: Invalid LaTeX alignment symbol: d{5.5}.
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:33
  [2] _latex_alignment
    @ ~/.julia/packages/PrettyTables/gNyx5/src/backends/latex/private.jl:58 [inlined]
  [3] |>
    @ ./operators.jl:966 [inlined]
  [4] _latex_table_description(ptable::PrettyTables.ProcessedTable, vlines::Symbol, left_vline::String, mid_vline::String, right_vline::String, hidden_columns_at_end::Bool)
    @ PrettyTables ~/.julia/packages/PrettyTables/gNyx5/src/backends/latex/private.jl:79
  [5] _pt_latex(io::IOContext{Base.TTY}, pinfo::PrettyTables.PrintInfo; tf::LatexTableFormat, body_hlines::Vector{Int64}, highlighters::Tuple{}, hlines::Nothing, label::String, longtable_footer::Nothing, sortkeys::Bool, table_type::Nothing, vlines::Nothing, wrap_table::Bool, wrap_table_environment::Nothing)
    @ PrettyTables ~/.julia/packages/PrettyTables/gNyx5/src/backends/latex/print.jl:109
  [6] _pt(io::IO, data::PrettyTables.ColumnTable; alignment::Vector{Symbol}, backend::Val{:auto}, cell_alignment::Nothing, cell_first_line_only::Bool, compact_printing::Bool, formatters::Nothing, header::Tuple{Vector{Symbol}, Vector{String}}, header_alignment::Symbol, header_cell_alignment::Nothing, limit_printing::Bool, max_num_of_columns::Int64, max_num_of_rows::Int64, renderer::Symbol, row_names::Nothing, row_name_alignment::Symbol, row_name_column_title::String, row_number_alignment::Symbol, row_number_column_title::String, show_header::Bool, show_row_number::Bool, show_subheader::Bool, title::String, title_alignment::Symbol, kwargs::Base.Pairs{Symbol, LatexTableFormat, Tuple{Symbol}, NamedTuple{(:tf,), Tuple{LatexTableFormat}}})
    @ PrettyTables ~/.julia/packages/PrettyTables/gNyx5/src/private.jl:411
  [7] #_pretty_table#61
    @ ~/.julia/packages/PrettyTables/gNyx5/src/private.jl:275 [inlined]
  [8] #pretty_table#53
    @ ~/.julia/packages/PrettyTables/gNyx5/src/print.jl:694 [inlined]
  [9] maketable(d::NamedTuple{(:a, :b), Tuple{Vector{Int64}, Vector{Float64}}}) =#

This looks correct to me, and I checked that it works with git and 1.8.0, and doesn’t work with 1.7.3 or 1.6.7, so it’s probably just a bug.

You’re missing an import line

julia> import PrettyTables._latex_alignment

Invoking julia with --compiled-modules=no also fixes it.

I do not think this is correct: Modules · The Julia Language

I have always used this OtherModule.f(x) = ... syntax without an import, especially when adding definitions to Base.* methods for custom types so that I don’t have to import them one by one explicitly.

Indeed, import does not seem required.
It works well here in 1.7.3, in a fresh REPL session.

REPL sesssion
julia

(@v1.7) pkg> activate --temp

(jl_iOafTJ) pkg> add PrettyTables

julia> using PrettyTables

julia> function PrettyTables._latex_alignment(s::Symbol)
           if (s == :l) || (s == :L)
               return "l"
           elseif (s == :c) || (s == :C)
               return "c"
           elseif (s == :r) || (s == :R)
               return "r"
           else
               # Allow arbitrary alignments.
               return String(s)
           end
       end

julia> function maketable(d)
           pretty_table(d; tf=LatexTableFormat(), alignment=[:r,Symbol("d{5.5}")])
       end
maketable (generic function with 1 method)

julia> maketable((;a=[1,2,3], b=[10.1,20.2,30.3]))
maketable((;a=[1,2,3], b=[10.1,20.2,30.3]))
\begin{table}
  \begin{tabular}{rd{5.5}}
    \hline\hline
    \textbf{a} & \textbf{b} \\
    \texttt{Int64} & \texttt{Float64} \\\hline
    1 & 10.1 \\
    2 & 20.2 \\
    3 & 30.3 \\\hline\hline
  \end{tabular}
\end{table}

julia> versioninfo()
Julia Version 1.7.3

It might be worth trying in a fresh session,
and maybe with julia --startup-file=no,
in case something in your startup.jl is interfering.

Yeah, in a fresh session it’s not a problem. If you’ve used it at least once already, even indirectly (by calling a function that ultimately calls this), then you need an explicit import. In general, it’s just safer to do it anyway, since you can’t be sure what’s been in your call chains so far.

Julia explicitly allows you to override existing methods and handles the resulting method invalidations by itself.

Note that you changed from PrettyTables#master to PrettyTables. This should not affect how method overriding works, yet changes behaviour here.

Indeed, with PrettyTables#master the behavior is exactly as you described.
Overwriting PrettyTables._latex_alignment after a first call to maketable (which errors) fixes it.

But it might be better to pkg> dev PrettyTables, apply your fix, and file a PR when it works.

Yet I guess that we are now two interested in an explanation,
if someone knows what’s going on :slight_smile: .

Can I force the piracy to take effect using eval or something? It is inconvenient to have to get an error before using the function so I would like to force it.

Not so! Here’s a fresh session in which I call Base.:*, then overwrite that method without ever using import.

julia> 2.0 * 2.0
4.0

julia> function Base.:*(x::Float64, y::Float64)
         println("piracy!")
         Base.mul_float(x, y)
       end

julia> 2.0 * 2.0
piracy!
piracy!
4.0
4 Likes