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

Wouldn't it be nice if anonymous functions inside type def are considered inner constructor? #8502

Closed
tonyhffong opened this issue Sep 28, 2014 · 17 comments

Comments

@tonyhffong
Copy link

What I have in mind was:

type MyType
    a::Int
    function( x::Int )
        new(x)
    end
end

I already declare the type name above, why do I have to repeat myself inside?

@StefanKarpinski
Copy link
Sponsor Member

That's actually a rather nice idea.

@rfourquet
Copy link
Member

+1, I never liked (since c++) this redundance, which is error prone (particularly at the REPL when types are renamed). I wouldn't mind a more explicit name though, like __init__ (one line form: __init__(x) = new(x) vs x->new(x)).

@StefanKarpinski
Copy link
Sponsor Member

The real advantage is that it avoids the fact that for parametric types defining methods for the type name inside the type block means something different than it does outside. This could make it less confusing.

@jakebolewski
Copy link
Member

Why can't new take the type it's constructing as the first argument?

MyType(x::Int) = new(MyType, x)

Wouldn't that remove the need for inner constructors?

I guess losing the inner / outer constructor concept for types would lead to some increased verbosity (as you would have to define all constructors) but it seems conceptually simpler and would lead to more explicit code.

@StefanKarpinski
Copy link
Sponsor Member

Also not a bad idea.

@StefanKarpinski
Copy link
Sponsor Member

One big advantage of scoping new specifically to the type block is that it gives some control over how objects of a given type can be constructed since only code in the type block can do the construction.

@ivarne
Copy link
Sponsor Member

ivarne commented Sep 28, 2014

It will also conflict with the current approach with two default constructors (one converting) when no inner constructor is defined.

@jakebolewski
Copy link
Member

That is an advantage (currently) but I feel that the concept of restricting extensibility is going to come up in the future for generic methods as well. This way you could unify the concepts of extensibility between type constructors and methods as the two would be exactly the same.

Right now type construction is special cased, it is really the only place in Julia that is not "open by default". If I want to extend or modify how a type (with an inner constructor) is constructed I have to go in and edit the source code.

@ivarne I addressed that point, although I feel the only times you should use inner constructors is when you want to opt out of the default behavior.

@JeffBezanson
Copy link
Sponsor Member

I personally like that there is at least one thing in the language that
lets you enforce invariants.

@simonster
Copy link
Member

Another reason to keep new restricted to the type block is that otherwise "identify types (especially immutable) that are always fully initialized, to avoid undefined checks on their fields" from #3440 doesn't seem so tractable.

@JeffBezanson
Copy link
Sponsor Member

Going back to the issue topic, using this syntax for constructors is a nice idea, I agree. The biggest problem at this point is probably that allowing both is kind of confusing.

@StefanKarpinski
Copy link
Sponsor Member

We could phase out the current way and make this the new hotness.

@JeffBezanson
Copy link
Sponsor Member

In favor of the current approach, I would say

  • Inner and outer constructors look more similar.
  • It's not quite so nice for x->new(x) to be a constructor, but in general this is identical to the function (x) end syntax.
  • There are corner cases like writing global f = function (x) end in the type block. You might not want that to be a constructor; in any case it's less clear what it should mean.

@JeffBezanson
Copy link
Sponsor Member

Oh and also you can't use MyType(x) = new(x) syntax, which is kind of a problem.

@simonster
Copy link
Member

I'm not really in favor of changing things given the other points, but I think the similarity between inner and outer constructors may actually be a point of confusion for parametrized types.

@JeffBezanson
Copy link
Sponsor Member

See #8135 for some thoughts on changes to inner constructors. I hope there is something we can do to improve the situation.

@tpapastylianou
Copy link

Would this kind of change still easily allow the use of secondary inner constructors? (i.e. an inner constructor that makes use of the primary inner constructor, but still needs access to the type block, such that it couldn't simply be replaced with an outer constructor)

i.e. can this:

type Foo
  x::Int
  y::Int

  function Foo(arg::SomeSpecialisedType)   # primary constructor
    // do something complicated involving x and y 
  end

  function Foo(arg::SomeOtherSpecialisedType) # secondary constructor
    // do something complicated involving x, y, and the primary constructor
  end
end

be replaced to this:

type Foo
  x::Int
  y::Int

  PrimaryConstructor = function(arg::SomeSpecialisedType)
    // do something complicated involving x and y 
  end

  SecondaryConstructor = function(arg::SomeOtherSpecialisedType)
    // do something complicated involving x, y, and the PrimaryConstructor variable
  end
end

To me these are very different. Not least because this makes SecondaryConstructor a closure which carries PrimaryConstructor along with it as a callable field (right?)

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

8 participants