Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

instance property declarations need to be in constructor scope #2

Closed
erights opened this issue Sep 17, 2015 · 41 comments
Closed

instance property declarations need to be in constructor scope #2

erights opened this issue Sep 17, 2015 · 41 comments

Comments

@erights
Copy link

erights commented Sep 17, 2015

The proposal as of 9/17 places both instance property declarations and static property declarations inside the class body. For static properties, this is exactly right, as static properties are per-class and are initialized once when the class is initialized.

For instance properties, putting the declaration in the class body is exactly wrong, because instance properties are per-instance precisely in order to vary from one instance to another. The expression used to initialize an instance need to be in the scope of the constructor, as the initial value will often be calculated based on constructor parameters.

The most common response to this objection is that the constructor can re-initialize these properties by assignment. But this confuses initialization with mutation. A declarative property declaration syntax needs to be able to grow into the ability to declare const properties, i.e., non-writable, non-configurable data properties. Whether the ability to declare const properties is provided by syntax or by declaration, their unassignable nature prevents this re-initialization in the constructor.

To make this repair to the proposal, we of course need an alternate concrete syntax proposal. Here are some choices:

Overload the variable declaration syntax

The common ES6 way to give an instance properties is by assignment in the constructor body, such as:

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

The first proposal would simply turn these assignments into declarative property initializations by prefixing them with let or const:

class Point {
    constructor(x, y) {
        const this.x = x;
        const this.y = y;
    }
}

This syntax is unambiguous, as it is currently illegal under the ES6 grammar.

Using the const keyword declares the property to be a non-writable, non-configurable data property. Using the let keyword makes a writable, non-configurable data property. Conceivably, using the var keyword would make a writable configurable data property, although there's not much point since assignment already does this. In all cases, these declarations could be decorated.

In a base class as above, perhaps all these declarations must come textually before the first non-declaration use of this, in order to prevent the instance from being observed before it is initialized. In a derived class constructor, perhaps all these declarations must come before the super call, while this is in a temporal dead zone, for the same reason. However, either of these requirements impedes refactoring ES6 code to turn instance assignment into initialization.

Use the reserved "public" keyword

This proposal is like the previous one, but using (and using up) the reserved "public" keyword rather than overloading the meaning of let and const:

class Point {
    constructor(x, y) {
        public this.x = x;
        public this.y = y;
    }
}

or perhaps

class Point {
    constructor(x, y) {
        public x = x;
        public y = y;
    }
}

By default, this makes writable non-configurable data properties. To declare a non-writable property instead, you'd use a decorator.

Since public, unlike let and const, is not already associated with a TDZ concept, the initialization-time considerations above do not have as much force. Nevertheless, observing an uninitialized instance is a hazard that these restrictions can help programmers avoid.

Another possible advantage of public is that private fields might then be declared with the same syntax but using the keyword private.

Use C++-like property initialization syntax

class Point {
    constructor(x, y)
      :x(x), y(y) {
    }
}

Personally I find it ugly. With decorators, they'd be even uglier. I list it because, given precedent, it should at least be mentioned as a candidate.

@littledan
Copy link
Member

Would these public or let/const member declarations be allowed in other places besides the top level of the constructor? For example, could they be in a conditional?

@erights
Copy link
Author

erights commented Sep 17, 2015

@littledan My inclination is to say "no". If you want to use control-flow (e.g., a conditional) to determine what the initial value is, where that control-flow code does not need access to this, just place those control-flow statements prior to the initialization. This works for let, const, and public. It works much less well for a C++-like syntax.

@littledan
Copy link
Member

Would this be done by syntax (a new production for top-level StatementListItems in a constructor) or static semantics rules? Should you put these declarations before or after a call to super()? Can they come after other code in the constructor?

One nice thing about the prior proposal is that it follows all of these restrictions in the right way, without the risk of unintuitive syntax errors.

@jeffmo
Copy link
Member

jeffmo commented Sep 18, 2015

Would this be done by syntax (a new production for top-level StatementListItems in a constructor) or static semantics rules?

I'm inclined to say it needs to be syntax for two reasons: (a) It needs to be unambiguously clear that this is a declaration and part of the class's declared structure (and not just expando initialization) (b) [related to (a)] It needs to be possible for userland libraries, test frameworks, meta-programming utils, etc to introspect (at least) and ideally interact with the declared structure of a class.

(b) is also one reason I'm slightly concerned with moving property initializers into the constructor. It mingles the declared structure of the class with the constructor initialization logic making it difficult for outside utilities to make changes to this structure in "userland". This mingling is one of the primary problems this proposal aims to solve. Test utilities that wish to mock parts of a given class are one example of a use case where userland might need to adjust class structures at runtime.

One possible workaround for this could just be to thunk the initializer expression that sits in the constructor just like we're doing now -- allowing reflection APIs to reach in and mingle still.

It's not completely clear to me yet why fulfilling declared+uninitialized fields in the constructor is a problem, though?

@rossberg
Copy link
Member

+1 to Mark's analysis and suggestion. It isn't super-pretty, but given the syntactic constraints of classes, it seems like the most adequate option.

@jeffmo, what do you mean by "fulfilling"? Mark noted that initialisation needs to be distinguished from mutation. So we would still need to invent special syntax for the initialisation of attributes (and tools would still potentially need to mess with that as well). At the same time, separating declaration from initialisation is more verbose because you have to enumerate each attribute twice. What's gained by that?

@rossberg
Copy link
Member

FWIW, I strongly favour using the public keyword, because that (1) requires fewer syntactic hoops, (2) extends cleanly to private properties, and (3) also fits nicely with TypeScript-style property declaration in constructor parameters (constructor(public x, public y)).

@jeffmo
Copy link
Member

jeffmo commented Sep 18, 2015

@jeffmo, what do you mean by "fulfilling"? Mark noted that initialisation needs to be distinguished from mutation.

By fulfillment I meant what Mark referred to as mutation. You've restated his point here as well, but my question is why? It seems there is little benefit to the underlying machinery (no types, so predicting memory layout remains a problem)...

So what's the motivation for not separating the two given that a constructor is "guaranteed" (barring abrupt returns, etc) to run in any circumstance that a property initializer is guaranteed to run?

I agree a superficial benefit is that it is less verbose. Is that all?

we would still need to invent special syntax for the initialisation of attributes

Why would we need to do this?

@rossberg
Copy link
Member

rossberg commented Sep 18, 2015 via email

@jeffmo
Copy link
Member

jeffmo commented Sep 18, 2015

function constant(target, name, descriptor) {
  return {
    ...descriptor,
    set: function(value) {
      var currDescriptor = Object.getOwnPropertyDescriptor(target, name);
      Object.defineProperty(target, name, {
          ...currDescriptor,
          configurable: false,
          writable: false,
          value,
      });
    },
  };
}

class Foo {
  @constant setOnce;

  constructor(injected) {
    this.setOnce = injected;
    this.setOnce = 42; // throws;
  }
}

@rossberg
Copy link
Member

rossberg commented Sep 18, 2015 via email

@jeffmo
Copy link
Member

jeffmo commented Sep 22, 2015

@rossberg-chromium: I think anything decorator oriented is going to be difficult to statically type by general and conventional means.

If one wishes to type property decls, it's already useful to extend the syntax with type annotations. Extending further with decl prefix tags (or whatever) is still possible for systems like typescript or flow. In a similar vain, systems like sound-typescript could arguably provide runtime decorators like '@constant' that assert contracts known to the type checker. There are probably several other options here in the same vein.

@domenic
Copy link
Member

domenic commented Sep 22, 2015

class Point {
    constructor(x, y) {
        public this.x = x;
        public this.y = y;
    }
}

I could achieve the same affect with s/public//g. So this syntax is useless to me.

class Point {
    constructor(x, y) {
        public x = x;
        public y = y;
    }
}

public is longer than this., so I'll prefer the latter.

@rwaldron
Copy link

FWIW, I was typing (nearly) the exact same responses as @domenic, but had to return to taking notes before I finished. Thanks @domenic for the succinct response.

@erights
Copy link
Author

erights commented Sep 23, 2015

@domenic, @rwaldron
If it is useless to have a distinct declaration of the shape of an instance, then this whole proposal is useless. If (as I think we actually all agree) it is useful, then I do not understand this objection.

@domenic
Copy link
Member

domenic commented Sep 23, 2015

The proposal as-is saves me typing. (No need for constructor() { super(...arguments); /* actual initialization here */ } Yours adds typing.

@erights
Copy link
Author

erights commented Sep 23, 2015

Is the purpose of this proposal merely to avoid some typing for an uncommon case? If that's it, I'd rather find a way to say "constructor" in fewer letters and be done with it. (Whether I would support such a proposal is another matter.)

@zowers
Copy link

zowers commented Sep 27, 2015

c# has instance properties on class level, and that's very useful feature.
instance properties can be initialized with new Klass() { instanceProp1=value1, instanceProp2=value2, }

@jeffmo
Copy link
Member

jeffmo commented Sep 29, 2015

@erights: Avoiding boilerplate is not the only purpose of this proposal but when it's possible to avoid, doing so is certainly appealing.

Currently there are 2 framework authors involved with this proposal (React and Ember) who can each cite prevalent patterns for their respective frameworks whereby non-constructor-dependent initialization will be common. The proposal shows one such example using React. I'm quite sure there are many other cases that will benefit equally as well such as auto-uuid initializers; And it is trivial to extrapolate the auto-uuid example into all sorts of less generic situations (csrf-token acquisition, registration of the instance while retaining a ref to the key in the registry, etc, etc).

Going back to the originally expressed concern, though:

A declarative property declaration syntax needs to be able to grow into the ability to declare const properties, i.e., non-writable, non-configurable data properties

Given the decorator described above, it seems clear that we can address the practicalities of single-initialization in userland in the interim at least. Moreover if we wish to include language level support for const properties at some point, a future proposal could ensure this by marking const fields non-configurable at the time the constructor evaluation is complete (thereby allowing configurability only during initialization and/or construction time). The current proposal also still offers the option of expansion to private properties by way of a similar syntax (a special #-prefix syntax perhaps, or maybe a private keyword). @wycats has shown how this can work in his big picture discussion.

After thinking this alternative through, however, it's become clear that there are some serious issues with it that just don't make sense. Namely the way that it places declarative descriptions about the class's prescriptive structure into an imperative statement-list position that executes at instantiation time. This introduces several bits of fall-out:

When do field declaration decorators run? (these need to run at class definition time) Where can field declarations be positioned with respect to super() inside the constructor? If they sit above super(), they cannot refer to this (this isn't allocated yet). Do we require that field definitions happen immediately after the super() call? What happens if some pre-initialization logic returns early (i.e. before the super())? In that case, did the field declarations count? It's a bit odd because they were added to the declarative definition of the class (observable via decorators + introspection), but yet they seem to be described conditionally? What happens if super() is itself called conditionally? What happens when a return or exception occurs in between or before field declaration statements come to execute?

The model here just doesn't make sense.

Ultimately we need a way to describe the fields on a class in terms of specified declarations that can be reflected and relied upon at instantiation time. Sometimes we wish to initialize those declarations with constructor-dependent data and other times not. The proposal as-is addresses both situations and does so in a familiar form that adds little complexity to the grammar and reduces boilerplate for a subset of use cases. I still find this to be the most compelling.

@rossberg
Copy link
Member

Given the decorator described above
#2 (comment),
it seems clear that we can address the practicalities of
single-initialization in userland in the interim at least.

I don't think we can count on decorators landing in the language anytime
soon, so they don't qualify as an interim solution. In fact, I believe (and
hope) that we get const fields much earlier.

Moreover if we wish to include language level support for const properties

at some point, a future proposal could ensure this by marking const fields
non-configurable at the time the constructor evaluation is complete
(thereby allowing configurability only during initialization and/or
construction time).

Such an approach would perhaps work, but also destroy half of the benefits
of declarative declaration forms.

After thinking this alternative through, however, it's become clear that
there are some serious issues with it that just don't make sense. Namely
the way that it places declarative descriptions about the class's
prescriptive structure into an imperative statement-list position that
executes at instantiation time. This introduces several bits of fall-out:

When do field declaration decorators run? (these need to run at class
definition time) Where can field declarations be positioned with respect to
super() inside the constructor? If they sit above super(), they cannot
refer to this (this isn't allocated yet). Do we require that field
definitions happen immediately after the super() call? What happens if
the pre-initialization logic returns early (i.e. before the super())? In
that case, did the field declarations count? It's a bit odd because they
were added to the declarative definition of the class (observable via
decorators + introspection), but yet they seem to be described
conditionally? What happens if super() is itself called conditionally?
What happens when a return or abrupt completion occurs in between or before
field declaration statements come to execute?

The model here just doesn't make sense.

Indeed, although I think part of the problem is also that we screwed up
super. It shouldn't have been that "flexible".

@jeffmo
Copy link
Member

jeffmo commented Sep 29, 2015

I don't think we can count on decorators landing in the language anytime soon, so they don't qualify as an interim solution.

I am working closely with @wycats to ensure that these two proposals co-evolve. They are still separate for sake of modularity, but decorators are very much on a track to surface in a similar timespan as this one.

On Sep 29, 2015, at 3:06 AM, rossberg-chromium notifications@github.com wrote:

I don't think we can count on decorators landing in the language anytime
soon, so they don't qualify as an interim solution.

@PinkaminaDianePie
Copy link

For all, who think what the main goal of this proposal is removing constructor word and saving few bytes of code - nope, main goal is providing declarative way for entire class description. With declarative class description we can run some logic on class declaration, providing it additional behavior or change something, what you can not do with simple mixins. This achieves with class decorators, whose target is class fields. Class decorators is not only tool for modifying field descriptors, it can be used as declarative API of frameworks, constructing application logic, based on your fields and its decorators. Good example of this is "Hibernate" - java framework and its ORM. In that framework main logic is based on annotations (java's analogue of decorators). You are only create some classes for your models and put some annotations, which grub all needed information and build DB schema and other stuff. And all your code is remains declarative, you dont need to write any imperative pieces of code for schema creation, you just need to describe your data models. Its very easy-readable and clean. With class fields and decorators you can write very clean frameworks in javascript. I have tried to do this for myself (with babel support of course) and realized that its a very powerfull feature. With class fields+decorators+async/await you can make frameworks such powerful as rails. For now on rails you can write a few times less code than on best javascript frameworks, but es7 should change this.

@rossberg
Copy link
Member

rossberg commented Oct 2, 2015 via email

@Elephant-Vessel
Copy link

Don't forget that this concept of "class" is something that is quite well used in many different programming languages and that it's generally valuable to keep the nature of these reusable and reoccurring concepts sticking to the de facto norm. And as far as I know, most commonly used class-based OOP-languages have the same structure as originally proposed by jeffmo. The default initialization value also tends to be limited to a compile-time constant value which prevents us from trying to initialize the field with data that would be runtime-dependent, where we can leave these dependencies on runtime that do exist to the constructor.

"because instance properties are per-instance precisely in order to vary from one instance to another". But in practice, it often makes sense to have a default value that can be changed per-instance if and/or when needed.

And note that the main value of field declaration in classes is not to have somewhere to initialize fields, but to provide both the developers and the tooling with a way to structure and communicate the nature of the class, and then it makes a lot of sense to treat declaration of both fields and method and both statics and dynamics in the same way, in the same place, in the source code to reduce unneeded complexity. We could separate the declaration and initialization completely and leave the later completely up to the constructor if we wanted to, in line with the original proposition as having the initialization optional, but we would still gain the communicative benefit of having a clear well-ordered definition of the nature of the class is one place. That we often can initialize them in the same place is probably just a thing of convenience.

@b-strauss
Copy link

JavaScript engines already optimize code based on the properties of an object created in it's constructor. I doubt EcmaScript will ever deprecate dynamic property setting, so these two ways to create properties (inside/outside of constructors) will need to work alongside each other anyway. Hence the main benefit I see in this proposal, as it currently stands, is the reduction of boilerplate code and easier detection, for the human eye as well as for tools like IDEs, of how an object looks like.

I am almost certain that the majority of developers, including me, would see no benefit in this code and would be too lazy to write it down.

class Point {
    constructor(x, y) {
        public this.x = x;
        public this.y = y;
    }
}

class Point {
    constructor(x, y) {
        public x = x;
        public y = y;
    }
}

@erights
Copy link
Author

erights commented Feb 5, 2016

JavaScript engines already optimize code based on the properties of an object created in it's constructor.

Yes. The purpose of the various forms of this proposal are not optimizations, though it is worth pointing out that non-configurable properties are potentially more efficient that configurable ones.

I doubt EcmaScript will ever deprecate dynamic property setting,

Correct. Though with a good enough alternate, old practice may fade slowly over decades. We are seeing the beginnings of this now as the class pattern displaces the manual encoding of classes by writing functions and manually initializing prototype chains.

so these two ways to create properties (inside/outside of constructors) will need to work alongside each other anyway.

Here, you assume your conclusion -- that initialization happens outside constructors. I have heard no argument for that I find compelling.

Hence the main benefit I see in this proposal, as it currently stands, is the reduction of boilerplate code

The only argument I have heard that I understand is this reduction in boilerplate. But that only makes sense for classes without constructors. That in turn only makes sense of these properties are then "initialized" post construction by assignment rather than initialization. This turns what should have been a declarative initialization into an imperative mutation, which is not something we should encourage. It is bad for code clarity to both humans and tools.

and easier detection, for the human eye as well as for tools like IDEs, of how an object looks like.

As I understand the main proposal, the properties it creates are not even non-configurable, and so not any kind of reliable indicator of an object's shape. With the only meaningful initialization being post-construction, it also obscures the property's meaning.

@michaelficarra
Copy link
Member

@erights

As I understand the main proposal, the properties it creates are not even non-configurable

You understand incorrectly. The properties are non-configurable.

@erights
Copy link
Author

erights commented Feb 5, 2016

@michaelficarra Good, thanks.

@b-strauss
Copy link

The only argument I have heard that I understand is this reduction in boilerplate.

@jeffmo already raised several questions:

When do field declaration decorators run? (these need to run at class definition time) Where can field declarations be positioned with respect to super() inside the constructor? If they sit above super(), they cannot refer to this (this isn't allocated yet). Do we require that field definitions happen immediately after the super() call? What happens if some pre-initialization logic returns early (i.e. before the super())? In that case, did the field declarations count? It's a bit odd because they were added to the declarative definition of the class (observable via decorators + introspection), but yet they seem to be described conditionally? What happens if super() is itself called conditionally? What happens when a return or exception occurs in between or before field declaration statements come to execute?

Besides these I think there is also, like @Elephant-Vessel said, the problem of unfamiliarity which should not be overlooked. Most OO mainstream languages structure their classes this way. Putting the initializers inside the constructor will not only introduce several strange corner cases like mentioned above, it will make people wonder why they should use this syntax in the first place, if the good old this.x = 5; would seemingly do the same thing, with fewer characters, for them anyway.

One should also think about the popularity about something like TypeScript that already does this at the syntax level. They already have a large community and my guess is with the release of Angular2 it will grow even larger. I don't think this proposal should introduce something that is unfamiliar to so many people.

@littledan
Copy link
Member

@michaelficarra What was the motivation for making the properties nonconfigurable?

@rossberg
Copy link
Member

rossberg commented Feb 8, 2016

@jeffmo https://github.com/jeffmo already raised several questions:

When do field declaration decorators run? (these need to run at class
definition time) Where can field declarations be positioned with respect to
super() inside the constructor? If they sit above super(), they cannot
refer to this (this isn't allocated yet). Do we require that field
definitions happen immediately after the super() call? What happens if some
pre-initialization logic returns early (i.e. before the super())? In that
case, did the field declarations count? It's a bit odd because they were
added to the declarative definition of the class (observable via decorators

  • introspection), but yet they seem to be described conditionally? What
    happens if super() is itself called conditionally? What happens when a
    return or exception occurs in between or before field declaration
    statements come to execute?

It's worth pointing out that much of this strangeness is due to super calls
being overly permissive. I think we screwed that up. Maybe there is room to
rectify some of that in the presence of property declarations, i.e.,
disallow some of the super() crazy liberties if property declarations are
present.

@erights
Copy link
Author

erights commented Feb 8, 2016

@rossberg-chromium

Maybe there is room to
rectify some of that in the presence of property declarations, i.e.,
disallow some of the super() crazy liberties if property declarations are
present.

Interesting. If the presence of private field declarations also caused these same super() crazinesses to be disallowed, perhaps the issues separating @allenwb and @zenparsing would also become non-issues. Since instance property declarations do result in non-configurable properties, if

  • mutable super chain
  • super override

were disallowed in the classes on the inheritance chain above a declaring class, then both declared instance properties and private fields could be allocated at fixed offsets in the object.

@rossberg-chromium Care to suggest something along these lines? Your recent experiences with what went well and badly in the StrongScript experiment should give us clues about what restrictions may be realistic.

@erights
Copy link
Author

erights commented Feb 12, 2016

@littledan just had a suggestion in chat with me that could apply to both declared properties and private state. Rather than require that the proto chain above a declaring class not be mutated, go the other way. Any class declared as extending a declaring class must also have an immutable proto chain up to that declaring class. This is practically a much milder requirement. I like it.

@littledan
Copy link
Member

I hope that whatever we go with for declaration syntax and semantics with respect to mutable prototypes, when the things get added, etc are the same between private state and property declarations. I definitely like the idea of making an immutable proto chain on classes using these features and their subclasses, and I think it could solve some of these problems, but we're left with super override, which might be harder to ban (at least subclassable builtins don't face the super override issue, so to the extent that what we do is motivated by consistency with them, proto-on-down freezing should be sufficient).

@zenparsing
Copy link
Member

@erights Regarding private state, if we want the built-ins to be directly self-hostable, we'll need to make a breaking change so that subclasses are given an immutable proto. Also, don't forget about Reflect.construct.

@erights
Copy link
Author

erights commented Feb 12, 2016

Hi @zenparsing I am studying your revised https://zenparsing.github.io/es-private-fields/ now. I am still entertaining both your and a subset of @allenwb 's pov on this ( https://github.com/wycats/javascript-private-state ) until I understand the implications better. (I don't mean to omit @wycats , Allen's co-author. I do only because I have talked to Allen about this and not to Yehuda.) Just to be clear to everyone, my comments immediately earlier in this thread, your response, and my comments below presume such a subset of an Allen-style treatment of state. However, I am not yet advocating either one.

@erights Regarding private state, if we want the built-ins to be directly self-hostable, we'll need to
make a breaking change so that subclasses are given an immutable proto.

That is correct. I think this is a change we could get away with. We have successfully made technically breaking changes before, that were not practically breaking of actual non-test code.

Also, don't forget about Reflect.construct.

Say more, within an Allen-style treatment of state?

@zenparsing
Copy link
Member

With Allen's original proposal, you have to be very careful to distinguish between initialized and uninitialized instances, because Reflect.construct can always be used to create uninitialized instances where an object has all of the necessary slots, but all of those slots are set to undefined.

class C {
    #x = 1;
}

Reflect.construct(Object, [], C); // { #x: undefined }

Now it's true that having an undefined field value will probably produce an error at some point when we attempt to use it within a method, but I would prefer an earlier TypeError on access if it's not the case that the relevant constructor has executed or is on the call stack.

Allen has suggested addressing this by making each field TDZ instead of undefined on creation. But at that point we are in effect no longer free of shape transitions anyway, which is one of the things that the static design was trying to accomplish.

I was hopeful early on that we could somehow restrict the power of Reflect.construct when private fields were at play (for instance, by throwing if the NewTarget argument has private fields associated with it), but that didn't seem feasible when I last considered it. If I remember correctly, such a restriction would break the equivalence between super() and return Reflect.construct(BaseClass, [], new.target).

@fatfisz
Copy link

fatfisz commented Apr 25, 2016

May I suggest a little something that I haven't seen in this discussion yet:

class Foo {
  fields { // or any other keyword
    field1 = expression,
    field2 = expression,
    ...
  }

  method() {
  }  
  ...
}

I know this adds more chars than maybe is necessary, but this way the fields are separated from the methods, which can hint that they receive special treatment. Everything else stays the same as it is now (the structure can be figured out at parse time, etc.). What do you think @erights?

@erights
Copy link
Author

erights commented Apr 26, 2016

@fatfisz This doesn't address my concern with this proposal. At the last tc39 meeting, @dtribble made an observation that completely flipped my opinion of this proposal. Even though property name lookup is not by lexical scope at all, there is still a lexical-scope-like intuition by which everyone intuitively understands any class syntax: The fields (properties, instance variables, ...) defined by the class are useful throughout the code of the class, i.e., the code of all the methods of the class. Thus, my suggestion of putting the declarations into the constructor, which is nested within the class body, is breaks the intuition, since the methods that would use these declared names do not visually seem to appear within a scope in which these names were defined.

Your suggestion a) has this problem, and b) does not solve the original problem which concerned me: that the initialization expressions will typically be data dependent on the constructor arguments.

@fatfisz
Copy link

fatfisz commented Apr 26, 2016

Right, completely missed that.

@littledan
Copy link
Member

@erights Based on @dtribble's argument, is this bug resolved?

@erights
Copy link
Author

erights commented Apr 27, 2016

@littledan Good point! Closed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests