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

Update event.md - the description is hard to understand #42509

Merged
merged 2 commits into from
Sep 23, 2024

Conversation

mpostol
Copy link
Contributor

@mpostol mpostol commented Sep 9, 2024

The description is hard to understand. It uses circular references to the word event and refers to an undefined term, namely `pub;lisher class".

Summary

Describe your changes here.

I propose a new description of the event keyword without referring to the meaningless event word.
The publisher class must be defined as a placeholder of the event variable but must not be defined referring to the event term.

Fixes #Issue_Number (if available)


Internal previews

📄 File 🔗 Preview link
docs/csharp/language-reference/keywords/event.md docs/csharp/language-reference/keywords/event

The description is hard to understand. It uses circular references to the word event and refers to an undefined term, namely `pub;lisher class".
@mpostol mpostol requested review from BillWagner and a team as code owners September 9, 2024 14:39
@dotnet-bot dotnet-bot added this to the September 2024 milestone Sep 9, 2024
@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates PR is created by someone from the .NET community. label Sep 9, 2024
@BillWagner
Copy link
Member

Hi @mpostol

I agree that the existing text needs updating. However, I have a number of concerns with the proposed changes. I want to avoid the use of the term "pointer". Pointers are valid in C#, and are different than events. Accessibility is also related, but not really part of the use of the event keyword.

I'd start with the first sentence in the standard on events:

An event is a member that enables an object or class to provide notifications. Clients can attach executable code for events by supplying event handlers.

That still requires more, but from that start, we can add how events build on delegates: A type raises an event by invoking all the event handlers (which are delegates) interested in the event. An event handler is a delegate that has been added to the list of delegates to invoke when an event is raised.

Does that sound like a better approach? What else do you think is needed?

@mpostol
Copy link
Contributor Author

mpostol commented Sep 9, 2024

@BillWagner thanks for the answer.

I agree with you that the documentation must be consistent so if there is a definition we must follow it. So for me, the priority is consistency. But we must also avoid logical errors like "enables an object or class ". Talking about objects we are talking about run-time. Objects are created at run-time by instantiating reference types. The documentation is about compile time so we can only talk about class as a type. But type (including but not limited to class) is only a text (snippet of a program). so the sentence "enables an object or class to provide notifications" is logically inconsistent for me, because the class is only a text so it doesn't have any behavior (it describes behavior but it is a huge difference). Let me give you an example

public class MyClass
{
    public delegate void MyDelegate(string message);
    public event MyDelegate MyEvent;
}

Can we agree that MyEvent is a variable - a value holder because we can assign value to it?
Can we agree that MyDelegate is this variable type?
Can we agree that public is an access modifier to the MyEvent variable?
Can we agree that access to the selected operations is not symmetric in the context of the MyClass boundary?
Can we agree that we are talking only and only about compile-time syntax and semantics of the text?

BTW where I can find the definition of the pointer term?

@mpostol
Copy link
Contributor Author

mpostol commented Sep 9, 2024

@BillWagner again,

Using Copilot: A delegate in C# is a type that represents references to methods - so maybe we should replace a method pointer with a method reference in my proposal?

Unfortunately in this definition, there is a next error because delegate is also a variable not only a type, for example

public class MyClass
{
    public delegate void MyDelegate(string message);
    public MyDelegate delegateVariable;
}
  1. Can we agree that delegate is the keyword used to declare a delegate type?
  2. Can we agree that the MyDelegate is the type?
  3. Can we agree that the delegateVariable is a variable ( a value holder) prefixed by the public access modifier?
  4. Can we agree that all operations (including invoking all members added in advance to the delegateVariable ) are visible outside the class boundary?

Let me stress

  1. I am not a native speaker.
  2. I have not reviewed the documentation so I am not sure about the consistency of my proposals.

@mpostol
Copy link
Contributor Author

mpostol commented Sep 9, 2024

@BillWagner Sorry for step by step refinement. Let's look at the ANTLR definitions:

event_declaration
    : attributes? event_modifier* 'event' type variable_declarators ';'
    | attributes? event_modifier* 'event' type member_name
        '{' event_accessor_declarations '}'
    ;
  1. variable_declarators is a list of identifiers that are variables, isn't it?
  2. member_name is a variable identifier, isn't it

Why not

member_name = variable_declarator; 

@SamHobbsOrg
Copy link

The term pointer was used in another discussion but I think it was used inappropriately in that discussion. In the context of .Net the appropriate term is reference . The term pointer is relevant to unmanaged languages and interfacing with them.

@SamHobbsOrg
Copy link

SamHobbsOrg commented Sep 10, 2024

The following is my understanding and possible confusion. If any of the following is incorrect then it might be a deficiency in the documentation.

I think the fundamental problem is that the event keyword is used in C# in a very confusing manner. A fundamental design criteria for the language is that it be readable yet I think this is an example of a violation of that.

The term event is a term used with all multiprocessing operating systems. Events are synchronization objects. IBM Mainframe operating systems had events half a century ago. Windows had (has) events in the original 16-bit versions of Windows, as in Using Event Objects (Synchronization) - Win32 apps | Microsoft Learn.

In .Net there are ManualResetEvent and AutoResetEvent classes. Yet the event keyword seems to mean something very different.

I wish people would not call everything a keyword. When there is a specific name for what something is then the documentation should say what the keyword is. I can't find an explanation of what the event keyword is. Is it an attribute? A modifier? A type? Something else? The language specifications even does not specify what the event keyword is. Very frustrating.

event keyword - C# reference | Microsoft Learn is the (this?) programming documentation of event. Note that it says that the event keyword declares an event. Further down is something interesting. It says:

Events are a special kind of multicast delegate

Whereas in other contexts, such as for other operating systems including the Windows API, an event is very different. Microsoft's use of the term event in the context of .Net seems to be inconsistent with the typical use of the term. If that is correct then the documentation definitely needs clarification.

@mpostol
Copy link
Contributor Author

mpostol commented Sep 10, 2024

My point is that we must state without any doubt if we are talking about keywords or a generic term.

If we are talking about a keyword (we are talking about a programming language) we must provide

  1. syntax definition: sequence of letters and where it can be used (event keyword may be used as a prefix of a delegate variable)
  2. semantic definition: meaning for all possible usages (defines a delegate variable with changed access modifiers for selected operations making them private despite the access modifier of the declared variable)

In this context, a field is a variable defined as a member of the class.

If we are talking about generic terms we must provide descriptions that improve the common-sense meaning of derived terms, e.g. communication, notification, publisher, callback, method invocation, polymorphism, level of abstraction, etc. Let me stress that all are derived from the delegate and event variables.

Again, in terms of the language:

  1. The delegate keyword is used to declare the delegate type
  2. The event keyword is used to declare the event variable (example)
  3. the delegate variable is a variable (field, parameter, local variable) of the delegate type.
  4. the event variable is a delegate variable with limited visibility of some operations

The best should be if both are consistent

Check out this section of my book to learn more Inter Layer Communication

@BillWagner
Copy link
Member

Hi friends,

Good discussion, but I think this may be expanding a lot in scope.

First, the language reference is meant to be an informal companion to the standard (the C# Language Specification). It shouldn't disagree with the spec, but it isn't as complete. It also isn't as formal. From that goal, here's some specific answers:

I also understand the concern regarding non-English speakers. I want to be very clear on terms both so the reference is consistent with the specification and to make our translations more correct. By using consistent terms, those are translated consistently.

With that, a number of specific comments:

Can we agree that MyEvent is a variable - a value holder because we can assign value to it?
Can we agree that the delegateVariable is a variable ( a value holder) prefixed by the public access modifier?

No. A field like event isn't a variable. Field like events support += and -=. You can't assign a value to a field as you can to a variable. We should refer to this as "adding a handler" or "removing a handler"

Can we agree that MyDelegate is this variable type?

Yes.

Can we agree that public is an access modifier to the MyEvent variable?

Yes, but see "variable" comment above.

Can we agree that access to the selected operations is not symmetric in the context of the MyClass boundary?

I'm not certain I understand your question. But I think I agree, and this is because a field like event isn't a variable.

Can we agree that we are talking only and only about compile-time syntax and semantics of the text?

Yes.

Can we agree that delegate is the keyword used to declare a delegate type?

Yes.

Can we agree that the MyDelegate is the type?

Yes.

Can we agree that all operations (including invoking all members added in advance to the delegateVariable ) are visible outside the class boundary?

I think so.

On the grammar questions:

  1. variable_declarators is a list of identifiers that are variables, isn't it?
  2. member_name is a variable identifier, isn't it

Yes to both.

Why not

member_name = variable_declarator; 

Because member_name might include an explicit interface implementation. (Something like IEnumerable<MyType>.GetEnumerator().

Comments on pointer:

Pointers in C# are allowed only in unsafe code. We shouldn't use that term when discussing these concepts.

event and keyword, etc:

Well, event is a keyword. Keywords can't be used as identifiers. So, it's important that we classify it as such.

C# events can represent Windows events. I'm not sure I understand that comment.

And, to close this:

Again, in terms of the language:

  1. The delegate keyword is used to declare the delegate type
  2. The event keyword is used to declare the event variable (example)
  3. the delegate variable is a variable (field, parameter, local variable) of the delegate type.
  4. the event variable is a delegate variable with limited visibility of some operations

The best should be if both are consistent

I think that's very close:

The delegate keyword is used to declare the delegate type.
The event keyword declares an instance of the delegate type and supports add and remove operations (or += and -=).
The instance of the delegate is a property that supports add and remove. (That handles both the 3rd and 4th items above).

I hope that helps us get to a good definition to edit this PR.

@mpostol
Copy link
Contributor Author

mpostol commented Sep 11, 2024

HI @BillWagner; thanks for the discussion, One more thing.

Look at

It is a declaration defining the event and an assignment statement simultaneously. The assignment statement, as far as I know, is available only for variables, isn't it? This operation is visible at compile time only and only inside the class, so the visibility is not symmetric.

I agree that it is a special variable because it holds a reference to set. Hence we can only add or remove members of this set. Review the mathematical set theory. Unfortunately inside the class (publisher), we can also remove all members (assign null) or assign a set with a single member, can't we?

Because member_name might include an explicit interface implementation. (Something like IEnumerable<MyType>.GetEnumerator().

  • not sure but you may be right. Let me stress that thanks to many "simplifications" (many thanks from my students) a reference to the method (delegate value) could be instantiated implicitly (no new operator), for example, lambda expression
public event Func<int, int> square = x => x * x;

Can we agree that the x => x * x; is a method (anonymous but a method with one parameter x and one return statement returning value x * x
Can we agree that we are creating a reference to this method in this assignment statement (right side of the = operator
Can we agree that we are adding this reference (a reference to an instance of a delegate value) to the set and assigning a reference to this set to an event (variable?)
Can we agree that this operation (assignment) is visible inside the class defining the field as its member only?

There is only one question, how broad the meaning must be scoped to make the documentation consistent, and how to explain this to someone wanting to only use this language, say engineer? In my opinion, by "Simplifying" the language syntax we are making semantics hard to understand.

Fortunately, according to my experience, event implementation is always the same but the description is completely different so it could create frustration. In all the cases I know event always is a set of references to methods. The signaling event can be read as "invoking all members of this set". Callback in other words.

Rdgs,
Mariusz

@SamHobbsOrg
Copy link

First, the language reference is meant to be an informal companion to the standard (the C# Language Specification). It shouldn't disagree with the spec, but it isn't as complete. It also isn't as formal. From that goal, here's some specific answers:

IBM documents computer languages differently. See Enterprise COBOL for z/OS documentation library. They have both a programming guide and a language reference. The programming guide is like the documentation that Microsoft provides. I think it is unfortunate that Microsoft omits details from the documentation that is relevant to the use of their software that is considered too technical.

C# events can represent Windows events. I'm not sure I understand that comment.

My understanding is that when the event keyword is used in C# it is used to provide something very different from most other uses of the term event. In most uses there is a set and reset status. As in the ManualResetEvent and AutoResetEvent classes and for the event objects in the Windows API. For C# event provides a list of delegates, right? Does event provide set and reset statuses? My understanding is that it does not. Therefore that needs to be emphasized and clarified.

  1. The delegate keyword is used to declare the delegate type
  2. The event keyword is used to declare the event variable (example)

That is very confusing. The term variable is essentially synonymous with name. I do not understand what more that it implies in this context. If it is appropriate to say that event declares a list, something like that, then that would be useful.

The delegate keyword is used to declare the delegate type. The event keyword declares an instance of the delegate type and supports add and remove operations (or += and -=). The instance of the delegate is a property that supports add and remove. (That handles both the 3rd and 4th items above).

That helps. I think it is important that the documentation make that clear. Except, does event declare an instance of the delegate type without the delegate keyword? If not then I think it is confusing to say that the event keyword declares an instance of the delegate type. This is where it helps to specify what the event keyword is. Is it a type? I think that it is not. It is an attribute or modifier or something like that. I think a clear definition of what the event keyword is would help.

@mpostol
Copy link
Contributor Author

mpostol commented Sep 12, 2024

Hi All,

The term variable is essentially synonymous with name.

I disagree, for me the variable is a placeholder for a value, so there is an available assign operation, for example, field. local variable, parameter, etc, Identifier of the variable is only a name that must be unique in the visibility scope used to distinguish it from others.

Does event provide set and reset statuses?

Yes. But the "set" and "reset" in your sentence I read as requests to change a condition and notify the result by activating sth (callback, scheduler, etc)

  • reset (resetting event example)
  • set += actually, it is adding the next member to the existing set or adding a reference to a new set populated with one member as in the following example
  public event Func<int, int> square = x => x * x;
  • we also may notify the event (condition) by using the event variable as the invocation of all methods (if any) pointed by it (already added to the set), for example (event notification)

@SamHobbsOrg the ManualResetEvent and AutoResetEvent are classes (reference types) but not events. My understanding is that both represent a condition that can be changed using operations like set and reset. These operations must not be interrupted by any concurrent activity to protect consistency. The operations could change the condition and invoke operations related to the scheduling mechanism. It doesn't necessarily need an event as the language construct (as far as I remember my PhD dissertation). Maybe the Event suffix in the names is confusing but we must not refer to these classes talking about the language construct "event". As we talk about the language definition we must not simultaneously talk about the type declarations provided by the language except types tightly coupled with the language constructs like IDIsposable, IEnumerable, etc.

According to my understanding, we must distinguish between the event keyword, event variable, event concept, event type, event handler, and event term. For me, it is the main reason we are discussing it late after the language was proposed for the first time.

@BillWagner
Copy link
Member

@mpostol @SamHobbsOrg

This conversation has expanded in scope. I'd like to do one of two things:

  1. Scope this back down to the definition of event. I think the keys are:
    1. Events are the means for a class or object to notify clients that something happened. A class or object raises the event.
    2. Clients attach delegates to an event by adding the delegate to the declared event.
    3. Clients can also remove delegates from the declared event.
    4. It's valid for an event to have no subscribers. In that case, the event object is null.
  2. Move this discussion to an issue to discuss a more extensive edit to this article, and possibly the conceptual docs on events.

What are your thoughts?

@mpostol
Copy link
Contributor Author

mpostol commented Sep 19, 2024

@BillWagner, I opt for point 1. It is imperfect, but I recognize it as a step in a good direction. In your proposal, consider only the definition of the subscriber and publisher roles. You are referring to subscribers, but there is nothing about publishers. You said, Events are the means... but what does that mean in terms of the language? Maybe replace the means with member. It leads to Events are the members.... BTW, can events be declared as members of structs? I like the proposal that instead of a reference to method you are using the delegate term (Clients attach delegates ...). I understand that it is a value of the delegate type.

Go ahead.

Independently I will work on a video explaining this topic in more detail. By design, it will be a section in my new book addressing delegates, events, communication, callback, and reactive programming in the context of program architecture and anonymous function. Hopefully, this video will be a good starting point for entering a discussion and proposals for conceptual docs on events later.

@SamHobbsOrg
Copy link

  1. Events are the means for a class or object to notify clients that something happened. A class or object raises the event.

The fundamental topic is the event keyword. How does the event keyword do anything to notify the clients? If it does the notification then that needs to be explained. Because as best as I understand things, the event keyword just creates a list of a specified delegate type that has appropriate overloads for adding and removing. The actual calling of the delegates is done by something else.

  1. Clients attach delegates to an event by adding the delegate to the declared event.

Attach as in adding to the list, correct?

  1. Clients can also remove delegates from the declared event.

Remove as in detach, correct? Remove as in removing from the list, correct?

  1. It's valid for an event to have no subscribers. In that case, the event object is null.

That is consistent with an empty list, correct?

I think discussions here of the use of the term event in other contexts is relevant to any developer familiar with the term in other contexts. The most important point I think is that the event keyword means something different from all other contexts that the term event is used. Perhaps if that is established then I don't need to spend an hour or more trying to provide specifics. For example the following is documentation of what relevant events are for the IBM Mainframe environment.

Copy link
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @mpostol

I made an edit to your original text this morning. LMK what you think.

docs/csharp/language-reference/keywords/event.md Outdated Show resolved Hide resolved
@BillWagner
Copy link
Member

@mpostol

BTW, can events be declared as members of structs?

Yes. However, the can't be declared as members of ref struct types.

Just suggestions: An ***event*** is a member that enables notifications to be triggered. Clients can attach executable code for events by supplying ***event handlers***. The `event` keyword declares an ***event***. The event is of a delegate type. While triggering an event all supplied event handlers are invoked. Event handlers are delegate instances added to the event. Event users can add or remove their event handlers to/from an event.

Co-authored-by: Bill Wagner <[email protected]>
@BillWagner BillWagner enabled auto-merge (squash) September 23, 2024 13:22
@BillWagner BillWagner merged commit 298c7fd into dotnet:main Sep 23, 2024
8 checks passed
@mpostol mpostol deleted the patch-1 branch September 23, 2024 15:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community-contribution Indicates PR is created by someone from the .NET community. dotnet-csharp/svc lang-reference/subsvc
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants