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

unclear behavior of statements inside type definition #9443

Closed
goretkin opened this issue Dec 23, 2014 · 12 comments
Closed

unclear behavior of statements inside type definition #9443

goretkin opened this issue Dec 23, 2014 · 12 comments
Labels
docs This change adds or pertains to documentation

Comments

@goretkin
Copy link
Contributor

For some reason, I forgot I wasn't inside a function, and I did this

julia> immutable Foo
       T = Int
       a::T
       end
ERROR: T not defined

After I remembered I was inside a type definition, I concluded that statements are ignored or variables don't get set. But you can do this

julia> immutable Goo
       T = Int
       warn("$T")
       a::Int
       end
WARNING: Int64

The error happens before "runtime" (I don't know a better name) because

julia> immutable Goo
       T = Int
       warn("$T")
       a::T
       end
ERROR: T not defined

(Julia Version 0.3.4-pre+47)

@vtjnash vtjnash added the docs This change adds or pertains to documentation label Dec 24, 2014
@vtjnash
Copy link
Member

vtjnash commented Dec 24, 2014

like (nearly) all block constructs in julia, type introduces a new scope that gets executed as it is compiled. that means T is now a local variable, accessible to any code defined in the same code block (e.g. a constructor). for example:

julia> immutable UID
         next_uid = 0
         my_uid::Int
         UID() = (uid = next_uid; next_uid += 1; new(uid))
       end

julia> UID
UID

julia> UID()
UID(0)

julia> UID()
UID(1)

julia> UID()
UID(2)

improved doc for this would be appreciated.

it's unclear to me whether your initial example is actually a bug or just not necessarily. as it stands now, the code to the right of the :: is executed in the global scope at compile time to resolve the type reference

@mauro3
Copy link
Contributor

mauro3 commented Jan 26, 2015

It could potentially be quite powerful if one could do computations on/with type-parameters like in the first example. Essentially this would be staged types #8472. Example:

type A{T}
    if T==Int
        a::Int
    else
        a::Float64
        b::Int
    end
    A(x::Int) = new(x)
    A(x,y) = new(x,y)
end
A(x::Int) = A{Int}(x)
A(x,y) = A{:nt}(x,y)

@StefanKarpinski
Copy link
Member

Yikes. Powerful certainly, but I feel like it might be too powerful.

@mauro3
Copy link
Contributor

mauro3 commented Jan 26, 2015

Of course one realizes that ifs with types is not very julian. Instead multiple dispatch staged types seem more natural:

type A{T<:Int}
    a::Int
    A(x::Int) = new(x)
end
A(x::Int) = A{Int}(x)
type A{T}
    a::Float64
    b::Int
    A(x,y) = new(x,y)
end
A(x,y) = A{Any}(x,y)

(but still, compting with types inside type-declarations would be useful, e.g. emulating triangular dispatch...)

;-)

@JeffBezanson
Copy link
Member

related: #5790

@elextr
Copy link

elextr commented Jan 26, 2015

This does however allow what are effectively class variables, but you have to use constructors as setters.

@mauro3
Copy link
Contributor

mauro3 commented Feb 9, 2015

@elextr, interesting, you mean like this:

julia> type A
           fl
           a=5
           A(;newa=error("reset a")) = a=newa
           A(x) = new(x+a)
       end

julia> A(4)
A(9)

julia> A(newa=10)
10

julia> A(4)
A(14)

@elextr
Copy link

elextr commented Feb 10, 2015

@mauro3 like this which reminds me I offered to document that but got distracted, my bad.

@mauro3
Copy link
Contributor

mauro3 commented Feb 10, 2015

Yes, that looks about the same: use one constructor to set/get the internal variable. As this is a pretty neat, if not much used feature. Probably worth conserving if we introduce default values.

@StefanKarpinski
Copy link
Member

You can use a let block (inside or outside of the type block) to get this, which is probably clearer anyway.

@mauro3
Copy link
Contributor

mauro3 commented Feb 10, 2015

Sounds good: let-blocks for class/type-variables and normal assignment for default values.

@brenhinkeller
Copy link
Contributor

brenhinkeller commented Nov 18, 2022

The current (v1.8.3) error messages for the original examples are quite a bit more informative now and make it clear that you cannot do this inside a type definition, so I think we can close this as completed -- but feel free to undo if you disagree!

julia> struct Foo
              T = Int
              a::T
              end
ERROR: syntax: "T = Int" inside type definition is reserved around REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[2]:1

julia> struct Goo
              T = Int
              warn("$T")
              a::Int
              end
ERROR: syntax: "T = Int" inside type definition is reserved around REPL[3]:1
Stacktrace:
 [1] top-level scope
   @ REPL[4]:1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This change adds or pertains to documentation
Projects
None yet
Development

No branches or pull requests

7 participants