-
Notifications
You must be signed in to change notification settings - Fork 66
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
An update from the Design Safari on the INotifyPropertyChanged
scenario
#282
Comments
Wow, @AnthonyDGreen, your idea is amazing! The beauty of it, in my opinion, is that:
IMHO this last point is the strongest, and I think not clear enough in your description -- in your screenshots you handled INotifyPropertyChanged on the type itself, instead of on NotifyAttribute. Amazing work! A few suggestions
|
@AnthonyDGreen My first impression is that it sounds like a good solution. I'll have to re-read it a few times to let it all soak in, but it's pretty impressive! 😄
That's because it has to be handled on the type and cannot be handled in the attribute. The handler method needs to raise an event, and that can only be done from within the object that "owns" the event (I'm not sure if that's the right terminology). See @AnthonyDGreen's last bullet point before the "Today" section:
I have an aversion to underscores in method names, so I prefer the original naming proposal. 😄
I'm just thinking out loud on this one. I can see how this would easily slot into the proposed resolution logic, but is there a benefit to having a property-specific handler, as opposed to just not using an auto-property and putting that handler's logic in the setter? I guess by having the property-specific handler for one particular attribute, you could still specify other attributes and they would be handled using the normal logic. So yeah, I guess this makes sense.
I feel like this would open up a can of worms. If you let it work with "manual" properties, then it's a small step to want it in non-properties as well (subs, functions, custom constructors, event handlers, etc, etc). Maybe that's a good thing, but it feels like feature-creep. The idea works well for auto-properties because the compiler is already generating the body of the methods. This is just telling the compiler how to implement them.
As far as I understand, yes, your assumption that you could consume them from earlier versions is correct. The compiler is simply generating different IL - you could implement the exact same logic yourself by manually calling the handler methods inside a "manual" property. @AnthonyDGreen one thought that's popped into my head is when you have multiple attributes on a property, what determines the order that the handlers are called in? For example, you've got a |
There are much simpler ways to handle AOP like scenarios with INotifyPropertyChanged, and there is no need for heavy language's changes like dotnet/csharplang#107 or #194 or anything like that..
The problem is that SomeObjINPC must be instantiated everywhere in place of SomeObj, and currently this require changes in code that create SomeObj instances, which is very uncomfortable. To solve it, there must be method (similar to extension methods), that overrides process of creating instances.
So, compiler must detect this method, and use it to create instance of returned type.
Such New generator may also be used for other purposes |
@AnthonyDGreen if you agree with @reduckted 's point about order (the order listed) and you don't see implementation issues with that, perhaps include in proposal. I am also worried about ordering of the in-class code. I may not want to notify if validation fails. I'm somewhat concerned about returning a boolean. This slants the feature heavily to validation scenarios. I think there are variations that alleviate these concerns. I think this is cool and might be an interesting direction. It feels like a foundation to a more complete set of work. It looks most interesting at first review as a basis for community implementation(s) of a set of meaningful attributes. This keeps individual developers from having to write their own implementations while leaving the implementation very flexible and dynamic. I don't know how serious versioning problems would be in such a scenario. |
@KathleenDollard totally agreed about it being a basis for community implementations. VB thrives when community members can share abstractions with each other to be more productive. I wanted to try a mix of approaches out so a handler may return a @reduckted yes, the ordering in source is significant. In fact if you can see in my examples I had to put the Notify attribute before most other attributes since that's where I put the code to check for duplicate values. I could have factored that logic into its own handler, I just didn't. But in the case of Trim and ThrowOnNull I put those before Notify because one transforms the value and the other will just throw an exception. @bandleader @reduckted speaks the |
Hey Anthony, My thoughts: There are VB enthusiasts like us, who would love this feature. Those enthusiasts would like VB to be as (good/grown up/flexible/Professional/enter your adjective here) as C#. Basically, they are good C# developers, but like the VB Language “taste” better, so they use VB. And then there is the typical VB developer. He might use attributes, but I’m not sure if he writes them. He might use inheritance, but only “as directed”. This feature is for the C# VB developer, I think. It leaves out what feels like 80% of the TYPICAL VB audience, who do not know about when to use more than implicit inheritance (when creating a new WinForms form, e.g) or when to write custom attributes. And they should not need to know. So, as a voice for them I have to say: this feature is not for VB. It is WAY too complicated to use. I, however, would love it. Klaus |
If there was a VBContrib library, do you think it could have attributes available for use that the typical VB developer could embrace? That is where I see the potential value of this feature. |
I totally agree with @KlausLoeffelmann. Being in the advanced group, this concept is very appealing but I can't help but wonder if beginner and lower intermediate level developers will have the same level of interest. |
Would it be possible to include a 'precedence' property in the attributes? That way the compiler/parser can determine the order of execution of the associated code. If not then the method associated with a custom attribute could end up being called at the wrong time. |
I am concerned about the backing field. Take the case in #279 You don't use the backing field, but you'd still like to use validation features and mutating features like your Trim and AutoRound. I'm imagining a VBContrib style library that had people inherit from a ViewStateWrapper class and add attributes. How would they know that these attributes didn't work, or is there a way to make them work? Kathleen |
@KlausLoeffelmann - I think you insult VB.Net developers by suggesting that the good ones are actually just good C# developers looking for variety. I would argue that the best C# developers are actually just good VB developers investigating what all the fuss is about... :) Getting back on topic... I think this exactly the kind of thing that might encourage some of those 'typical' VB developers you refer to, to expand their horizons into the wonderful world of attributes, especially if there are handy libraries of helpers to ease their way into modern coding patterns, which they could then also more readily embrace (I know the pain of INotifyPropertyChanged has been enough to make me pack up my bags and go home early so that I could psyche myself up for a day of copy, paste and regex-replace....) |
Respectfully disagree. I'm also an advanced VB developer who also uses C#, but even if you're talking about beginners: where they don't understand something 100%, they are fine with copying from StackOverflow and adapting it to their needs. Remember that back in VB6 people were doing amazing things by copying some Win32 API code from PlanetSourceCode or CodeProject! But secondly, I don't think that VB is a beginner's language. It was never meant to limit developers, but to give them all the power possible as cleanly, beautifully and approachably as possible -- letting them not just start out programming but become master programmers in a syntax that is beautiful to masters, beginners, and laymen alike. That's why MS earlier had VB.NET on feature parity with C#; there's nothing about the language that throws advanced users away -- nor should we have any. Remember that VB6's popularity was the ability to make (in a fraction of the time and complexity) all the "regular" Windows desktop apps that were popular at the time. Today, people aren't making Windows desktop apps; they're making mobile apps (and some cross-platform and web apps) with MVC/MVVM frameworks. (An imperative WinForms app is simply not competitive today.) Inasmuch as INotifyPropertyChanged is necessary for that, this feature doesn't complicate things; on the contrary, it simplifies implementation of an inteface that is a basic necessity for giving users to power to make today's apps. |
I imagine the attributes would go directly into the BCL, because I am sure that other languages (like C#) will eventually want to take advantage as well. This isn't a VB-specific thing; it's a common need to have data classes with reduced boilerplate -- Scala for instance calls them "case classes."
In @AnthonyDGreen's design, the compiler passes the newly-being-assigned value to each attribute as
Why wouldn't we simply do it in the order the attributes were declared?
I propose that we need to find a way around this, whether that means cooperating with the CLR team, or simply using one of the 'hacks' available on the internet -- I did a quick search and found some interesting results. |
See my concerns above about code formatters reordering the attributes. |
@KathleenDollard : The only way I see this feature would make sense in the original spirit of VB was, if we considered @AnthonyDGreen 's concept to be rather infrastructure, and we put ready to use base classes and/or attributes in the My-namespace. VbContrib lacks discoverability for too many of the VB devs. We need to talk about updating My-Namespace anyway. The infrastructure of the compiler - just in case folks did not know that - already allows that without modifying compiler or framework libs. This would be another great community initiative, btw! @bandleader : I wouldn't call VB at all an exclusive beginner language, because it is not. Vb is a compromise Productivity vs. Flexibility. I'm just talking about approachabiliy and discoverability. We need new functionality to be picked up by the whole audience instantly. If the majority does not get it on first glance, they cold-shoulder it most probably. We need something which I'd call Guidance by Product. Things must be so intuitive that VB folks pick them up just like that. Things that made VB6 great were
And later in .NET
Functionality in that spirit can be the only unique selling feature for VB. Parity for everything to C# doesn't make and never made any sense. If I wanted everything like in C#, why wouldn't I take C#: Which is exactly what MILLIONS of devs did. VB had an identity crisis for a long time. We need to find a way to give it back it's own identity, it original self. Otherwise, VB will end up as a boring Zomby, which will only get those things which are needed to consume necessary platform improvements. Like Interface methods. Klaus |
I don't understand this mentality. We've got a good feature (yes, it could be improved and refined, but it's still good), but just because some developers who use the language wouldn't feel comfortable using it, we must throw it away? Why?
No one is forcing them to use it. For those of us who know how to use VB to it's full extent, this is a great idea, and we shouldn't be hamstrung by novice developers for fear of them not understanding it. Documentation and tutorials can help them. This sort of thinking is, in my opinion, what feeds the hatred and ridicule of VB.NET. The idea that the language is a "beginner language" and therefore must not contain advanced concepts or anything that's too complicated. This feature would be really useful for things like view models in an MVVM-based WPF application. If this "typical VB developer" is creating an MVVM-based WPF application, then surely they can understand this proposed concept. Maybe I'm just really out-of-step with what a "typical VB developer" is, given that I, and my colleagues at work, are all highly competent VB.NET developers. |
@reduckted: Couple of questions:
I am curious about what you and other people think! |
First of, I really love this idea. I like it has a hint of extensibility. To me that's a future safeguard, an avenue to deal with change and evolve without having to wait for a new version of VB with yet more keywords to deal with new frameworks or patterns. I would like to see more detail on how the compiler knows what to inline. Re typical VB developers... stuff 'em ;) Yes I said that. If they can't speak up for themselves I wonder if they should be programming in the next era. I think the biggest problems VB faces are the lack of community involvement; this notion that we can't have anything extensible because we need defined sandboxes and prescribed buckets and shovels. I don't believe the "average" VB developer doesn't use attributes, rather I believe they use them when they have to, designers, serialization, data contracts, etc. |
Completely with @reduckted and @Bill-McC on this one. Yes, Visual Basic is popular among beginners for various reasons, but as I said, why can't they continue to use it even once they're advanced programmers? Isn't that its whole value? The isn't MS's toy language. The goal here is to make it approachable for beginners to get started -- not to omit any feature that beginners will not be able to immediately use and understand. "VB is as powerful as other languages, but much cleaner, and with much more sugar and elegance." -- A Wise Man
"An entry-level language?" It doesn't prove that the language is unsuited to advanced developers, just that advanced VB developers are frustrated at MS's abandonment of it, and have left for C#.
This isn't about moving C# teams to VB, but about making each language as great as it can be. We don't need feature differentiators per se; it's a syntax preference. Simple feature parity would go a long way towards making VB viable.
That's not what's happening. MS is not improving VB and focusing on beginner-friendly features. They're improving C# and letting VB fall by the wayside.
Gold. See also what I wrote above about the amazing ability of beginning programmers' to copy code from StackOverflow (and actually improve their programming skills in the process). |
The impression I got from your comments was that it was too complicated: "this feature is not for VB. It is WAY too complicated to use."
I wrote "some" because that's what you said. You said "It leaves out what feels like 80% of the TYPICAL VB audience,". There's your percentage that you wanted. When I wrote "some", I was referring to the 80% that you came up with. |
Again: what do you think is the percentage? I am just trying to get a feeling if my estimation is shared by others. |
Even if you think this proposal is only for 'advanced' coders, I don't see how you can extrapolate that perspective into "this proposal doesn't belong in VB, because it's too advanced for VB coders" Besides the insult that is to advanced VB developers everywhere, VB has always been a tool for developers who want the improved productivity provided by VB, and the more skilled among them have used other (COM/ActiveX) languages or hooked into Win32 to get things done that are not natively available. So VB has always catered for 'entry level' and advanced users. So I'm puzzled by this argument that this proposal is too sophisticated for VB, because it may spook inexperienced or 'Typical VB' coders. If that's your view of VB, then what's the point of this forum? One could argue that VB already has all the features the 'typical' or 'inexperienced' coder, and if that was the target market for VB.Net, then the job is complete, except for bug fixing and performance improvements. But that's at best a naive view of the language, because you believe that VB is an 'entry level language', and that VB coders are by definition less skilled than, say, C# coders. At worst it's a malicious view of the language because you have some agenda to advance that involves the demise of future development of the language. |
@KlausLoeffelmann I don't think this feature is too complicated for most of the VB programmers to understand. We already have many features that depend on custom attributes. Such as extension methods, hide module name, PInvoke, COM interface import/export and thread fields. If this feature accompany with nice intellisense behaviors for build-in auto-implemented property handler attributes, they will get used to it swiftly. <Notify>
Public Property Count As Integer And press enter, or press the > key at the following position: <Notify Press ">" key here
Public Property Count As Integer If #Region "Auto-implemented property handlers"
' Visual Basic will handle auto-implemented properties' Set part with this Function if they have NotifyAttribute.
' Usage:
' <Notify>
' Public Property <PropertyName> As <PropertyType>
' For more information, please visit (doc link).
'''<Summary>
''' Raise PropertyChanged event when the property is being set to a different value.
''' </summary>
Protected Function NotifyOnPropertySet(Of T)(propertyName As String, ByRef backingField As T, value As T) As Boolean
If Object.Equals(value, backingField) Then Return True
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Function
#End Region |
Whoa, didn't see this conversation had heated up (was too busy packing). I think we're all mostly in what the language design meeting calls "violent agreement"; it looks like we disagree more than we actually do. @KlausLoeffelmann this is exactly as you describe it--infrastructure. I've describe a mechanism that could be implemented in the compiler to make it a little more productive to do certain kinds of things. I've also fleshed out the first draft of that design by trying to build a dozen example things. But that thing that would be "shipped" or advertised in a future version of VB would be those things. This mechanism would be a footnote, declarative MVVM would be the headline. In the way that Yes, many intermediate or advanced VB developers will eschew the pre-canned base class for their own base class but... so what. The goal is for first-time developer to be crazy productive out of the box. Adding a new ViewModel to a VB project should be as straight-forward as adding a new Form. So for just that top echelon of VB developers. The P/Invokers and compiler extenders and framework authors, I ask:
|
It can't really be worked around with the CLR team. To the CLR there are no "events" really. There are just (usually) public methods named |
Please consider also a Constructed Attribute as I proposed here: |
@VBAndCs I like your Constructed Attribute proposal and responded, but could you explain its connection with this proposal of Anthony's? |
@bandleader |
Four months ago (November, 2017), Visual Basic MVP Klaus Löffelmann (@KlausLoeffelmann) was invited to attend the VB LDM to present on the challenges of modern GUI programming. Klaus presented a few different patterns and important concerns from the field. Expectedly, the tedium of implementing
INotifyPropertyChanged
was chief among them. This left the LDM with a renewed interest in addressing this scenario.Klaus did a prototype he called
UserInterface
properties that used an attribute<UserInterface>
to generateINotifyPropertyChanged
implementations.I proposed a slightly more general approach called
WithPropertyEvents
(temporary keyword choice).Klaus convinced me it was too messy, I adapted his prototype into a proposal specifically targeting
INotifyPropertyChanged
called Bindable Classes and Properties that was what Klaus designed but with a keyword instead of an attribute.Klaus updated his prototype to use a keyword instead of an attribute but chose a different keyword.
The VB LDM revisited the iced proposal for compiler plug-in source generators and/or metaprogramming via Replacable Members for address this scenario.
The VB looked at the three proposals on the spectrum from most general and expensive (meta-programming/generators) to most specific, self-descriptive, and cheapest (
Bindable
/UserInterface
) and felt that meta-programming was too far out and too uncertain to block other ideas and that neither of the alternatives would dissuade the pursuit of meta-programming in the future. The middle optionWithPropertyEvents
was selected to move forward as it was cheap/fast and still not hard-coded to a particular UI pattern to bake into the compiler.Lots of comments were left on the proposal regarding possible keyword choices.
I started working on a prototype of
WithPropertyEvents
with a working title/keyword choice ofTemplate
properties, as it changed the code-gen of auto-props to resemble an implementation of the classic OOP Template Method Pattern.I consulted with various friends and former colleagues for feedback. This design simplified based on feedback from them and from exploring implementation approaches which reduced the complexity of the code-gen from a property set having multiple pluging points via well-named methods to a vastly simplified single method passing arguments ByRef.
More contention about keyword choice:
Template
doesn't mean much, which is both not very meaningful, yet marketable--like Services and Workspaces".Callback
properties".I had several concerns about keyword choice:
Template:Binding
is going to get old. A keyword and an identifier gives too much visual space to the meaningless keyword.Joinpoint
,Pointcut
, andAdvice
.Callback Properties
orAdvice Properties
.Template Properties
sounds more marketable (though still vague).Alex (and others throughout history have proposed an attribute). I don't like the idea of an attribute for a baked-in pattern, but for an open-ended mechanism it seems good. The problem is the attribute isn't in the same class as the property and can't raise any events in another object.
Today
I ended up abandoning the whole
Template
property design entirely in favor of an extensible attribute based model I've tentatively titled "Property Handler Attributes". It's pretty simple. Given the existence of a well-known abstract attribute type, e.g.PropertyHandlerAttribute
, if one or more attributes derived from said well-known type is applied to an auto-prop the code-gen for the setter (and potentially getter) of that auto-prop will:NotifyAttribute
->NotifyOnPropertySet
).Shared
methodOnPropertySet
is looked up on the attribute class itself. If found, the compiler will perform overload resolution passing theMe
parameter of the property (or null if the property isShared
, the name of the property, a reference to the backing field, and the value parameter, and invoke the method. This allows simpler handlers which don't depend on special access (like raising an event) or state and whose logic would be the same for any property on any class, e.g.ThrowIfNullAttribute
.Boolean
and the result of the invocation is true, the setter will return immediately, ignoring subsequent handlers AND the setting of the backing field. This allows for a handler which prevents mutation (FreezableAttribute
) or ignores duplicate sets (common inINotifyPropertyChanged
implementations).<MaxLength(25)>
.This latest iteration addresses the original scenario, is general, has a marketable semi-descriptive name imho, dodges the keyword naming debate, doesn't significantly complicate the compiler and potentially simplifies a lot of programs. It takes repetitive situations that force you to give up the declarative benefits of auto-props to write boilerplate setters and allows you to keep it declarative, which I believe is more in keeping with the spirit of the language.
I implemented the prototype, played with it, good stuff. Now I want to share and get feedback. Here's some screenshots that illustrate the value (I'll build a shareable prototype when I get to a real computer. I've implemented this on a wholly inadequate laptop that's painful to code on):
Here are the property declarations involved:
Here's what some instance handlers themselves look like:
Here're some shared handlers (implementations in attributes themselves):
Here's a doc comment helping a reader understand what an attribute does:
Here's an example of the program running, showing off one of the validator attributes:
The rest of the attributes I need to record interaction for you to see them work but...
Here's the generated IL for one of the setters:
And here's all the actual code for the various demos. Obviously most of this wouldn't ever appear in user-code:
Models
UI Code-Behind
And here's my prototype branch.
Now I'm off to the Baltimore airport for another riveting day of flying across the country. Feedback welcomed!
-ADG
The text was updated successfully, but these errors were encountered: