Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inner constructor #332

Closed
cstjean opened this issue Mar 3, 2017 · 11 comments
Closed

Inner constructor #332

cstjean opened this issue Mar 3, 2017 · 11 comments

Comments

@cstjean
Copy link
Contributor

cstjean commented Mar 3, 2017

Am I correct that the way to write a 0.5-compatible inner-constructor in 0.6 is

type Foo{T}
    x::T
    @compat (::Type{Foo{T}}){T}(x::T) = new{T}(x)
end

? If so, it is missing from the Compat README. I can make a PR.

@yuyichao
Copy link
Contributor

yuyichao commented Mar 3, 2017

No, you don't need the compat

@lobingera
Copy link

@yuyichao: And a 0.4 and 0.5 compatible inner-constructor?

@yuyichao
Copy link
Contributor

yuyichao commented Mar 3, 2017

That's already documented as 0.5 style call overloading syntax. We can certainly add something to the doc, just feels weird since there's nothing about inner constructors that's Compat related.......

@mauro3
Copy link
Contributor

mauro3 commented Mar 11, 2017

It is definitely confusing. Using an 0.5 constructor in Julia 0.6 gives:

julia> type Foo{T}
       x::T
       Foo(x) = new(x)
       end

WARNING: deprecated syntax "inner constructor Foo(...) around REPL[5]:3".
Use "Foo{T}(...) where T" instead.

But then using @compat in Julia-0.5 on the recommended syntax does not work (and cannot work, if I understand correctly because where cannot be parsed):

# julia 0.5
julia> using Compat

julia> type Foo{T}
       x::T
       @compat Foo{T}(x) where T = new(x)
       end
ArgumentError: @compat called with wrong number of arguments: (:(Foo{T}(x)),:where,:(T = new(x)))

julia> type Foo{T}
       x::T
       Foo{T}(x) where T = new(x)
       end
syntax: extra token "where" after end of expression

Anyway, either add a recommendation to the depreciation warning about how to code it 0.5 compatible, or add something to Compat.jl, as that is the place people turn to.

@nalimilan
Copy link
Member

The deprecation warning would better suggest the syntax which works on both 0.5 and 0.6.

@richardreeve
Copy link

As someone trying to update a package to work with 0.5 and 0.6, I'm finding it quite unhelpful that there's no way of writing inner constructors using this where syntax so it's backward compatible, and there's no obvious documentation to get things to work in both styles.

The best I can come up with at the moment is this:

using Compat
using DataFrames
@compat abstract type AbstractTypes end

immutable Taxonomy{FP <: AbstractFloat} <: AbstractTypes
    speciesInfo::DataFrame
    taxa::Dict{Symbol, FP}
    function (::Type{Taxonomy{FP}}){FP}(speciesInfo::DataFrame, taxa::Dict{Symbol, FP})
      sort(speciesInfo.colindex.names) == sort([keys(taxa)...]) || error("Taxon labels do not match similarity values")
       new{FP}(speciesInfo, taxa)
     end
end

function Taxonomy(speciesInfo::DataFrame, taxa::Dict)
   Taxonomy{valtype(taxa)}(speciesInfo, taxa)
end

which then allows me to call:

Taxonomy(DataFrame(Species=["sp1","sp2"], Genus=["gen1","gen1"]), Dict(:Species=>1.0, :Genus=>0.5))

but it's so untidy compared to what I'd write in either 0.5 or 0.6. If this is the best thing to do, could it be documented clearly somewhere, and if it's not could someone tell me how to write where so compat makes it work with 0.5?

PS Obviously, I'd like to remove immutable too...

@carlobaldassi
Copy link
Member

carlobaldassi commented Apr 25, 2017

@richardreeve I had the same issue and in the end I came up with a macro that you just prepend to the 0.5-style constructor, i.e. it allows you to write e.g.

type LocalFields{ET}
    lfields::Vector{ET}
    lfields_last::Vector{ET}
    move_last::Int
    @inner {ET} function LocalFields(N::Int)
        lfields = zeros(ET, N)
        lfields_last = zeros(ET, N)
        return new(lfields, lfields_last, 0)
    end
end

Here's the code:

wrapin(head::Symbol, fn, T::Symbol) = Expr(:curly, fn, T)
function wrapin(head::Symbol, fn, T::Expr)
    @assert Base.Meta.isexpr(T, [:tuple, :cell1d])
    Expr(head, fn, T.args...)
end

# horrible macro to keep compatibility with both julia 0.5 and 0.6,
# while avoiding some even more horrible syntax
macro inner(T, ex)
    VERSION < v"0.6.0-dev.2643" && return esc(ex)
    @assert Base.Meta.isexpr(ex, [:(=), :function])
    @assert length(ex.args) == 2
    @assert isa(ex.args[1], Expr) && ex.args[1].head == :call
    @assert isa(ex.args[1].args[1], Symbol)
    fn = wrapin(:curly, ex.args[1].args[1], T)
    fargs = ex.args[1].args[2:end]
    body = ex.args[2]

    return esc(Expr(ex.head, wrapin(:where, Expr(:call, fn, fargs...), T), body))
end

@richardreeve
Copy link

@carlobaldassi Thanks for that, it looks infinitely less ugly than what I'm currently wrestling with! I really need to learn how macros work - though having spend many years avoiding as much preprocessor nonsense as I could in other languages I already wish I hadn't felt I needed to say that :(

@TotalVerb
Copy link
Contributor

If we had #349 that would address this, but it's not trivial to do. Maybe a few easy cases could be supported first

@richardreeve
Copy link

That would be great. I appreciate the long term improved flexibility of the new system, but the fact that I'm going to have to spend a year making all of my code worse for backward compatibility reasons does not make me happy at all. I appreciate this is the fate of early adopters, but if there was an @compat fix like #349 then it would help me (everyone?!) write idiomatic Julia 0.6 this year rather than next...

@quinnj
Copy link
Member

quinnj commented Jan 21, 2018

I don't think this is relevant anymore (0.5 is no longer supported); feel free to re-open if that's not the case

@quinnj quinnj closed this as completed Jan 21, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants