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

Modern code review #1263

Merged
merged 46 commits into from
Nov 10, 2020
Merged

Modern code review #1263

merged 46 commits into from
Nov 10, 2020

Conversation

richlander
Copy link
Member

@richlander richlander commented Nov 7, 2020

I did a code review of the repo, moving to more modern patterns, including C# 9 syntax.

Filed dotnet/roslyn#49230 as part of this cleanup. Not important, but I surely won't be the last person to be unsure of is checks on Span<T>.

This PR removes about 1k LOC from the repo. A previous PR (#1243) removed a similar number of LOC. Next step is to start applying records throughout the codebase (#1258).

@ghost ghost added the area-device-bindings Device Bindings for audio, sensor, motor, and display hardware that can used with System.Device.Gpio label Nov 7, 2020
Copy link
Member

@Ellerbach Ellerbach left a comment

Choose a reason for hiding this comment

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

Nice clean up!

{
_i2cDevice = i2cDevice ?? throw new ArgumentNullException(nameof(i2cDevice));
_i2cDevice = i2cDevice ?? throw new ArgumentNullException($"{nameof(i2cDevice)} cannot be null");
Copy link
Contributor

Choose a reason for hiding this comment

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

You're only supposed to provide the name of the argument.
See https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception.-ctor?view=netcore-3.1#System_ArgumentNullException__ctor_System_String_
Otherwise if you want to add a message use the second parameter, but the above message would pretty much already be generated (and probably localized too). See
https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception.-ctor?view=netcore-3.1#System_ArgumentNullException__ctor_System_String_System_String_

Copy link
Member Author

Choose a reason for hiding this comment

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

Got it. I noticed that there are two patterns that are pervasive in the codebase. I apparently picked the wrong one. I didn't Have this background. I'll fix them all on a second PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

I added another commit with many instances of ArgumentException fixed, well beyond the initial scope of the PR. Good call.

{
throw new ArgumentOutOfRangeException(nameof(gpioInterruptPin), $"The given GPIO Controller has no pin number {gpioInterruptPin}");
}

_gpioInterruptPin = gpioInterruptPin;
_shouldDispose = shouldDispose;
_shouldDispose = shouldDispose || gpioController is null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't it be cleaner to have an overload that didn't take a controller, and remove the shouldDispose from there? It seems weird this parameter is only used if a value is provided. Similar example is the HttpClient that takes a handler had the dispose boolean but the handler isn't nullable - only if you use the overload that doesn't take a handler is one instantiated and shouldDispose set to true:
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs#L24-L28
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs#L130

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 feedback. That's something we could consider, but it gets complicated really quickly because of the interplay of GPIO and I2C or SPI. Some bindings have an overload for just GPIO and another for GPIO and I2C (or SPI) where GPIO is optional. It seems like optional parameters are a perfect match for this complexity. Also, this is really the only extra line that has to exist to allow it.

@@ -9,7 +9,7 @@

Console.WriteLine("Hello BNO055!");
using I2cDevice i2cDevice = I2cDevice.Create(new I2cConnectionSettings(1, Bno055Sensor.DefaultI2cAddress));
using Bno055Sensor bno055Sensor = new Bno055Sensor(i2cDevice);
using Bno055Sensor bno055Sensor = new (i2cDevice);

Choose a reason for hiding this comment

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

I'm personally not a big fan in this situation, using var seems a lot easier to parse to me. But I guess that's a style choice.
There's also not a lot of consistency in the pattern that's used in this, PR, some are using explicit types, some are using var, and this one is using target-typed new.

Copy link
Member Author

Choose a reason for hiding this comment

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

I used to be in the var camp. I switched as part of the last couple PRs I've done on this codebase. I've never spent so much time in a codebase in which I was totally unfamiliar. It's not a problem for construction, which this specific comment is about, but is a problem for readability for everything else. I've decided I'm not going to use var any more.

Copy link
Member Author

Choose a reason for hiding this comment

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

You are right that the PR isn't consistent on on this aspect. I'm trying some things. I still haven't figured out the right pattern. Fortunately, find and replace makes it somewhat straightforward to make changes.

Choose a reason for hiding this comment

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

I've decided I'm not going to use var any more.
😲🤯

@@ -285,7 +274,7 @@ private void DisableAlertReadyPin()
(byte)Register.ADC_CONFIG_REG_HI_THRESH, 0x7F, 0xFF
};
_i2cDevice.Write(writeBuff);
if (_gpioController != null)
if (_gpioController is object)
Copy link

Choose a reason for hiding this comment

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

at the risk of starting a war, I think is not null is more clear than is object. They generate the same code (is not null vs is object).

Adding @jaredpar to make sure dissenting opinions way in.

Choose a reason for hiding this comment

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

I sorta figured it isn't using not null due to language version requirements for the repo.
But in general re is object vs is not null, this feels like something that is going to keep coming up as people are opinionated on this; there's no technical advantage either way, it's purely preference driven.
So tl;dr, 🍿 (Hi Jared :)

Choose a reason for hiding this comment

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

I'm guessing that people are going to have to get used to seeing it both ways. People that are super in the weeds of C# like the language team might decide that is object is extremely clear to them and choose it in general. Other people working on their company LOB codebases might decide on is not null because it seems easier for Joe/Jane Developer to understand what's going on. Each team/codebase will choose what they feel is clear and understandable to them (and readers of the code), though what that means will vary in context.

Copy link

Choose a reason for hiding this comment

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

no reason to new set the lang version explicitly imho:

<PropertyGroup>
   <LangVersion>8.0</LangVersion>
</PropertyGroup>

{
_gpioController.Dispose();
_gpioController?.Dispose();
_gpioController = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Moving the nulling of _gpioController here means that if we called the constructor like
new Ads1115(i2cDevice, gpioController, 1, false, ...) then we would still keep the reference to the pass-in gpioController unlike the old code. Is this an intended change?

Copy link
Member Author

Choose a reason for hiding this comment

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

You are right. It would be better the old way. I was conflating the call to dispose and the assignment to null as related operations. They are not. Thanks for catching this.

Filed an issue on that: #1272


/// <inheritdoc cref="IDisposable" />
public void Dispose() => Dispose(true);
Copy link
Contributor

Choose a reason for hiding this comment

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

So happy to see trivial Dispose being handled trivially ;)

{
return Temperature.FromDegreesCelsius((CalculateTrueTemperature() + 8) / 160.0);
}
public Temperature ReadTemperature() => Temperature.FromDegreesCelsius((CalculateTrueTemperature() + 8) / 160.0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Would love to see these magic numbers be appropriately named const values

@@ -548,17 +536,14 @@ private void SetConfigMode(bool mode)
/// <inheritdoc/>
public void Dispose()
{
if (_autoDispoable)
if (_shouldDispose)
{
_i2cDevice?.Dispose();
_i2cDevice = null!;
Copy link
Contributor

Choose a reason for hiding this comment

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

Like other places, just because we're not _shouldDispose does that mean we should still keep the ref live in _i2cDevice or should we be nulling it outside the brace?

@@ -171,7 +171,7 @@ private void RunMotorSyncTime(BrickPortMotor[] ports, int[] speeds, int timeout)
}

// create a timer for the needed time to run
if (_timer == null)
if (_timer is null)
{
_timer = new Timer(RunUntil, ports, TimeSpan.FromMilliseconds(timeout), Timeout.InfiniteTimeSpan);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is _timer ever disposed/nulled? It is an IDisposable object and should be handled (which means this class should also be IDisposable

{
return result;
}

return 0;
}

public void Dispose() => _buzzer?.Dispose();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we be nulling _buzzer here?

_disposed = true;
}
}
public virtual void Dispose() => _lcdInterface?.Dispose();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we be nulling the _lcdInterface here?

richlander and others added 17 commits November 9, 2020 11:22
@richlander richlander merged commit 0b7733e into dotnet:master Nov 10, 2020
@richlander richlander deleted the projectreview branch November 10, 2020 15:15
@richlander
Copy link
Member Author

Thanks for all your help @IDisposable! Much appreciated. Thanks to everyone else for the feedback.

@richlander richlander mentioned this pull request Nov 10, 2020
ZhangGaoxing pushed a commit to ZhangGaoxing/iot that referenced this pull request Mar 15, 2021
* Code cleanup

* Update projects

* Project updates

* Fix breaks

* Update ExplorerHat project

* Update Ft4222 project

* Update GoPiGo3

* Update GrovePi project

* Update a few more projects

* More updates

* Update null checks

* Fix ArgumentException usage

* Apply suggestions from code review

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/GoPiGo3/GoPiGo3.cs

* Update src/devices/Ina219/Ina219.cs

Co-authored-by: Marc Brooks <[email protected]>

* Switch exception type

* Switch exception type

* Update src/devices/Mcp3428/Mcp342x.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Mcp3xxx/Mcp3xxx.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Mcp9808/Mcp9808.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Mlx90614/Mlx90614.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Ssd13xx/Ssd13xx.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Tcs3472x/Tcs3472x.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Vl53L0X/Vl53L0X.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Ws28xx/Ws28xx.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Hmc5883l/Hmc5883l.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Mpr121/Mpr121.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Mpu9250/Mpu6500.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Nrf24l01/Nrf24l01.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Pn5180/Pn5180.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Pn532/Pn532.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Pn532/Pn532.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/RadioTransmitter/Devices/Kt0803/Kt0803.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/RadioReceiver/Devices/Tea5767/Tea5767.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Rtc/Devices/Ds1307/Ds1307.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Rtc/Devices/Ds3231/Ds3231.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Rtc/Devices/Pcf8563/Pcf8563.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Seesaw/SeesawBase.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/ShiftRegister/ShiftRegister.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Shtc3/Shtc3.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update src/devices/Si7021/Si7021.cs

Co-authored-by: Marc Brooks <[email protected]>

* Update GoPiGo3.cs

* Update per feedback

* Add type in place of var

* Revert one switch expression to switch statement

* Add pragma for []?

Co-authored-by: Marc Brooks <[email protected]>
@github-actions github-actions bot locked and limited conversation to collaborators Dec 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-device-bindings Device Bindings for audio, sensor, motor, and display hardware that can used with System.Device.Gpio
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants