Skip to content

Conversation

Aaronontheweb
Copy link
Member

@Aaronontheweb Aaronontheweb commented Jan 20, 2025

Changes

This PR looks scarier than it is. I've implemented nullability on the ActorCell, the brains underneath each actor, in order to support some future changes we're going to make here. None of this should result in a behavior change or a breaking API change - practically speaking, given that most of these APIs are not called directly from user code.

Checklist

For significant changes, please ensure that the following have been completed (delete if not relevant):

@Aaronontheweb
Copy link
Member Author

I've also cleaned up A TON of TBD stuff in the XML-DOCS while I was at it. Didn't get everything, but got a lot of it.

Copy link
Member Author

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

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

Detailed my changes

Copy link
Member Author

Choose a reason for hiding this comment

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

API approval file - you should still look over it but there's nothing super scary here. Going to comment on the changes in the source files themselves.


private ImmutableDictionary<string, FunctionRef> FunctionRefs => Volatile.Read(ref _functionRefsDoNotCallMeDirectly);
internal bool TryGetFunctionRef(string name, out FunctionRef functionRef) =>
internal bool TryGetFunctionRef(string name, out FunctionRef? functionRef) =>
Copy link
Member Author

Choose a reason for hiding this comment

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

All of these TryGetValue<TKey, TValue> methods have a signature of bool TryGetValue<TKey, TValue>(TKey key, out TValue? val)in the .NET standard libraries - so I've brought theTryGetFunctionRef` up to speed.

Copy link
Member Author

Choose a reason for hiding this comment

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

So a really useful over-arching point for all of these code changes in the review:

We're not changing what is actually returned - we're just accurately annotating it going forward.

Please bear that in mind - only input behavior has changed (i.e. explicitly handling null inputs where we weren't before), not any output behavior. Methods that could return null before could still return null, but it's just annotated now.

/// <param name="actor">TBD</param>
/// <returns>TBD</returns>
public ChildRestartStats InitChild(IInternalActorRef actor)
public ChildRestartStats? InitChild(IInternalActorRef actor)
Copy link
Member Author

Choose a reason for hiding this comment

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

ChildRestartStats will be null if we don't have a child by this name - should never happen but it has always been theoretically possible

/// Tries to get the stats for the child with the specified name. This ignores children for whom only names have been reserved.
/// </summary>
private bool TryGetChildRestartStatsByName(string name, out ChildRestartStats child)
private bool TryGetChildRestartStatsByName(string name, out ChildRestartStats? child)
Copy link
Member Author

Choose a reason for hiding this comment

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

Again, the TryGetValue pattern applied here

/// Current message count inside the mailbox.
/// </summary>
public int NumberOfMessages { get { return Mailbox.NumberOfMessages; } }
public int NumberOfMessages { get { return Mailbox!.NumberOfMessages; } }
Copy link
Member Author

Choose a reason for hiding this comment

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

Mailbox can't be null by the time anyone calls this method - or else there's been a catastrophic failure.


SwapMailbox(mailbox);
Mailbox.SetActor(this);
Mailbox!.SetActor(this);
Copy link
Member Author

Choose a reason for hiding this comment

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

Mailbox can't be null by the time anyone calls this method - or else there's been a catastrophic failure.



Assert.Assert(instance != null, (string)(nameof(instance) + " != null"));
return instance!;
Copy link
Member Author

Choose a reason for hiding this comment

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

The assertion on the line above prevents this from ever actually returning null.

{
var current = Current;
return current != null ? current.Sender : ActorRefs.NoSender;
return current?.Sender ?? ActorRefs.NoSender;
Copy link
Member Author

Choose a reason for hiding this comment

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

Since Current can be null and Sender can separately be null (this has always been a possibility), we return ActorRefs.NoSender here - which, ironically, is null right now.

/// <param name="kvp">TBD</param>
/// <param name="index">TBD</param>
protected void ChildStatsAppender(StringBuilder sb, KeyValuePair<string, IChildStats> kvp, int index)
protected static void ChildStatsAppender(StringBuilder sb, KeyValuePair<string, IChildStats> kvp, int index)
Copy link
Member Author

Choose a reason for hiding this comment

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

Not a breaking change - moving to static would only change inheritors, not callers.

Copy link
Member Author

Choose a reason for hiding this comment

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

(and there could be no inheritors of this method before.)

* Add `NotNullWhen` compiler annotation attribute to all of the `bool TryX(out Y)` patterned functions
* Add assertions on all shebangs to make sure we document why the nullability check was overriden
/// <returns>TBD</returns>
public static IEnumerable<T> Concat<T>(this IEnumerable<T> enumerable, T item)
#nullable enable
public static IEnumerable<T> Concat<T>(this IEnumerable<T>? enumerable, T item)
Copy link
Member Author

Choose a reason for hiding this comment

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

Good call

/// </summary>
public static readonly IActorRef NoSender = null;
#nullable enable
public static readonly IActorRef? NoSender = null;
Copy link
Member Author

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@Arkatufus Arkatufus left a comment

Choose a reason for hiding this comment

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

LGTM

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

Successfully merging this pull request may close these issues.

2 participants