Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
LongSack
Jan 17, 2003

I, personally, do not turn my nullable warnings into errors, but since I’m anal about diagnostics, they might as well be.

The biggest downside to nullable reference types that i run across day-to-day is that the IDE doesn’t take into account that items injected from DI cannot be null since any missing dependency results in an InvalidOperationException so i find myself using bangs (!) on injected items since i know that they can’t be null. Or can they be? Is it possible to register
C# code:
services.AddTransient<IFooService,null>()
If it is, what kind of psychopath would do that?

Adbot
ADBOT LOVES YOU

QuarkJets
Sep 8, 2008

FlapYoJacks posted:

Same, and it's good. I have also ran into a ton of "senior" Python devs that have no clue what mypy, flake8, pylint, or black is, which is a bit disheartening. They also get really upset at first when their PR's are automatically rejected because one (or all) of those things don't pass. :v:

Yes, they could check locally. Yes, I have a make file where they could run `make jenkins` and it would puke out the same errors locally.

Yes, everything is built in a docker container, which means Jenkins and local builds are the exact same.


I get that black doesn't always make the most pretty choices, but it's still better than having every single file be a bespoke interpretation of how any one dev wants their code formatted. :v:

Pfft this is newbie poo poo, come back after you've become an experienced Vigil user

Ranzear
Jul 25, 2013

LongSack posted:

they might as well be [errors]

Sums it up for me. Languages that aren't totally type strict have their uses for it, but work fine without it and it's generally worth avoiding. A warning is sufficient but not to be ignored.

Languages that purport to be type strict but let anything be nullable are just nucking fonsense, and C# has even more layers of javascript-grade garbage on top, like arbitrarily getting zero or -231 if NaN is cast from double to int.

I've seen adjacent null and NaN checks on the same value, allegedly because of that. I don't ever want to subject myself to that level of sanity questioning. C# is 90% of my problem with Unity, and I'm the freak who likes javascript.

LOOK I AM A TURTLE
May 22, 2003

"I'm actually a tortoise."
Grimey Drawer

LongSack posted:

I, personally, do not turn my nullable warnings into errors, but since I’m anal about diagnostics, they might as well be.

The biggest downside to nullable reference types that i run across day-to-day is that the IDE doesn’t take into account that items injected from DI cannot be null since any missing dependency results in an InvalidOperationException so i find myself using bangs (!) on injected items since i know that they can’t be null. Or can they be? Is it possible to register
C# code:
services.AddTransient<IFooService,null>()
If it is, what kind of psychopath would do that?

null isn't a first-class type in C#, so you can't use it as a type parameter. However you would be able to inject null using this code:
C# code:
services.AddTransient<IFooService>(_ => null!);
What does your code look like where you're having issues with the compiler thinking your DI dependencies are nullable? I must be missing something. Are you using constructor injection?

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

LongSack posted:

So if you don’t use null, what do you do with a function like
C# code:
public Foo? ReadFoo(int fooId) { … }

When there is no Foo with that id?

The method name ReadFoo() implies to me that that method always returns a Foo, not null; and if it can't do that, then it throws.

If it can fail to return a Foo then it ought to be

public bool TryReadFoo(int fooId, out Foo? foo)

where foo is null if and only if the return value is false.

Ranzear posted:

Sums it up for me. Languages that aren't totally type strict have their uses for it, but work fine without it and it's generally worth avoiding. A warning is sufficient but not to be ignored.

Languages that purport to be type strict but let anything be nullable are just nucking fonsense, and C# has even more layers of javascript-grade garbage on top, like arbitrarily getting zero or -231 if NaN is cast from double to int.

I've seen adjacent null and NaN checks on the same value, allegedly because of that. I don't ever want to subject myself to that level of sanity questioning. C# is 90% of my problem with Unity, and I'm the freak who likes javascript.

turn checked arithmetic on

code:
using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            double d = double.NaN;

            int i = (int)d;
            Console.WriteLine(i);

            try
            {
                checked
                {
                    int j = (int)d;
                    Console.WriteLine(j);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
    }
}
code:
PS C:\Users\myname\source\repos\scratch\consoleapp1\bin\release> .\ConsoleApp1.exe
-2147483648
System.OverflowException: Arithmetic operation resulted in an overflow.
   at ConsoleApp1.Program.Main(String[] args) in C:\Users\myname\source\repos\scratch\ConsoleApp1\Program.cs:line 18
PS C:\Users\myname\source\repos\scratch\consoleapp1\bin\release>

Absurd Alhazred
Mar 27, 2010

by Athanatos
I'm probably showing my stupidity and C++/Windows API bias here, but how can you have a language with pointers that aren't nullable? How else do you initialize pointer variables if you need them around before you can source them with something meaningful? What should the return value of a pointer variable be if whatever was supposed to get that pointer to a dereferenceable state failed?

Qwertycoatl
Dec 31, 2008

Absurd Alhazred posted:

I'm probably showing my stupidity and C++/Windows API bias here, but how can you have a language with pointers that aren't nullable? How else do you initialize pointer variables if you need them around before you can source them with something meaningful? What should the return value of a pointer variable be if whatever was supposed to get that pointer to a dereferenceable state failed?

Languages with pointers that aren't nullable generally also allow you have pointers which are nullable, either as a variant on the pointer type or as an Optional<T> kind of thing, if you really need them.

If a function is supposed to return a non-nullable pointer and for some reason can't, it would throw an exception

LOOK I AM A TURTLE
May 22, 2003

"I'm actually a tortoise."
Grimey Drawer

Absurd Alhazred posted:

I'm probably showing my stupidity and C++/Windows API bias here, but how can you have a language with pointers that aren't nullable? How else do you initialize pointer variables if you need them around before you can source them with something meaningful? What should the return value of a pointer variable be if whatever was supposed to get that pointer to a dereferenceable state failed?

Think of it as a compile-time feature. At runtime there are always going to be ways to circumvent the non-null guarantees, but the compiler can prevent user code from accidentally dereferencing pointers that it thinks could be null.

Also, if your user code needs to declare a pointer some time before it can initialize it with a non-null value, it should be a nullable pointer. The existence of non-nullable pointers doesn't preclude the existence of nullables ones.

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.

Absurd Alhazred posted:

I'm probably showing my stupidity and C++/Windows API bias here, but how can you have a language with pointers that aren't nullable?
Well, for instance Rust has an optimization where pointers are Option<T>::Some(...) but a NULL pointer encodes to Option<T>::None. So there's no memory overhead compared to 'regular' (C-style) pointers, except on the type level there's this wrapper around them.

Absurd Alhazred
Mar 27, 2010

by Athanatos
So in C++ this would be the difference between using a reference (which should not be nullable, although I assure you I have seen (&reference_variable_oh_no_what_are_you_doing != nullptr) checks) and a pointer?

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Absurd Alhazred posted:

I'm probably showing my stupidity and C++/Windows API bias here, but how can you have a language with pointers that aren't nullable? How else do you initialize pointer variables if you need them around before you can source them with something meaningful? What should the return value of a pointer variable be if whatever was supposed to get that pointer to a dereferenceable state failed?

By having potentially-uninitialized pointers and immediately-initialized pointers belong to different types, at least at compile time.

Let's imagine * is reserved for classic potentially-uninitialized unsafe pointers and, I don't know, *! is for immediately-initialized safe pointers. The hypothetical "safe C++" would look like:

C++ code:
SomeStructType *safeP; // ok

// SomeStructType *!safeP; // compile error; safe pointers must be initialized

SomeStructType *!safeP = &someStructValue; // ok

if(someBool()) { *unsafeP = &someStructValue; }

SomeStructType x = *!safeP; // ok, guaranteed safe

// SomeStructType y = *unsafeP; // compile error, cannot dereference an unsafe pointer

SomeStructType z = *unsafeP || someDefaultStructValue; // hypothetical syntax for how to safely dereference an unsafe pointer, by providing a fallback value

if (*unsafeP != NULL) {
   /* modern compilers can do flow analysis, realize that in this 
       scope the pointer is not null (barring race conditions),
       and allow you to dereference it */	
   SomeStructType w = *unsafeP;

   /* Rust's famous borrow checker goes a step further and also protects 
       against race conditions, by checking that you didn't pass unsafeP to 
       any other function which might have touched it between the if() and
       the dereferencing.
   */
}

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Absurd Alhazred posted:

I'm probably showing my stupidity and C++/Windows API bias here, but how can you have a language with pointers that aren't nullable? How else do you initialize pointer variables if you need them around before you can source them with something meaningful? What should the return value of a pointer variable be if whatever was supposed to get that pointer to a dereferenceable state failed?

The exact same way as with any other non-pointer type. Suppose you have the following class:

C++ code:
class Foo {
public:
	Foo() = delete; // not default constructible
	Foo(int value); // does some nontrivial work
};
How would you write a local variable which stores a Foo but can't initialize it at the point of declaration, or write a function which maybe returns a Foo but might fail to do so (in a non-error way where throwing an exception would be inappropriate)? The normal way is to wrap it in a std::optional to get a nullable Foo in specifically the places where it needs to be nullable.

The big thing you need to avoid is not nullable types, but rather nullable types in places where the value can't actually be null, as that leads to thinking that a nullable type can't be null in places where it actually can be (or lots of unreachable error handling that is thus untested and will probably do subtly incorrect things when future changes make it no longer unreachable).

Absurd Alhazred
Mar 27, 2010

by Athanatos
Okay, so the original statement here:

Ranzear posted:

Unity-focused devs are fundamentally broken. Trying to explain to them that null should be regarded as an error, not a value, is a hopeless crusade. Null checking is a symptom, not a solution.

Never, ever, let them within ten feet of your databases.

was wrong? Because that's the context with which I'd been reading the rest of the posts, rather than a context of "clearly distinguish where null is an error and where null is a thing that can happen".

Foxfire_
Nov 8, 2010

I would disagree with that statement and regard unity's null checking sin as it taking what is normally a very fast operation and overloading it to be a very slow and expensive one. It makes normalish looking c# code run terribly unless you expect a hidden unity quirk

(Separately there are performance reasons to have game data be big dense arrays of value types instead of pointers off to scattered places, but that's a separate architecture decision)

SupSuper
Apr 8, 2009

At the Heart of the city is an Alien horror, so vile and so powerful that not even death can claim it.

Absurd Alhazred posted:

Okay, so the original statement here:

was wrong? Because that's the context with which I'd been reading the rest of the posts, rather than a context of "clearly distinguish where null is an error and where null is a thing that can happen".
When in doubt, the coding horror is Unity.

(Unity null is not the same as C# null)

ExcessBLarg!
Sep 1, 2001
I'm not following this Unity stuff. From what I gathered:
  • Unity overloads == so "== null" checks go down a slow path.
  • Devs shouldn't be doing null checks anyways because standard reference types can't be null (or at least, null is an error condition).
  • They might be doing null checks because it's a Nullable type, but they should be using Option types instead.
OK, but, if Unity is overloading ==, I'd expect the first two statements of the method to be (i) "is it null? return false" and (ii) "is it this? return true". Does Unity not do that because they think you shouldn't be doing null or identity checks in the first place, or that you should only use Object.ReferenceEquals? Or is the slow part even getting to the overloaded method in the first place?

FlapYoJacks
Feb 12, 2009
Serious question: Why would anybody choose Unity over Unreal? Is it simply a C++ vs C# thing? It also seems like Unity is cheaper as well vs royalties for UE yes?

FlapYoJacks
Feb 12, 2009
It took me several hours to figure out a bug in some legacy code. It's related to regex. It's also why I refuse to use regex in my code unless it's very simple.

I'm positive at this point that the plural of regex is regret

Absurd Alhazred
Mar 27, 2010

by Athanatos

FlapYoJacks posted:

It took me several hours to figure out a bug in some legacy code. It's related to regex. It's also why I refuse to use regex in my code unless it's very simple.

I'm positive at this point that the plural of regex is regret

:mods:

Selklubber
Jul 11, 2010
I made some python code this week using both regexes and nulls for the first time. Planning to put some stuff from dat into a postgresql database. how much pain should I prepare for?

Zopotantor
Feb 24, 2013

...und ist er drin dann lassen wir ihn niemals wieder raus...

FlapYoJacks posted:

It took me several hours to figure out a bug in some legacy code. It's related to regex. It's also why I refuse to use regex in my code unless it's very simple.

I'm positive at this point that the plural of regex is regret

Well, you know what they jwz says.

Jamie Zawinski posted:

Some people, when confronted with a problem, think “I know,
I'll use regular expressions.” Now they have two problems.

rarbatrol
Apr 17, 2011

Hurt//maim//kill.

FlapYoJacks posted:

It took me several hours to figure out a bug in some legacy code. It's related to regex. It's also why I refuse to use regex in my code unless it's very simple.

I'm positive at this point that the plural of regex is regret

Not long ago we discovered a sanitization-related regex wasn't using the compiled option (.NET), and it's used indirectly in thousands of places in the legacy code. Once we added that flag, several mysterious performance issues magically went away.

dwazegek
Feb 11, 2005

WE CAN USE THIS :byodood:

ExcessBLarg! posted:

I'm not following this Unity stuff. From what I gathered:
  • Unity overloads == so "== null" checks go down a slow path.
  • Devs shouldn't be doing null checks anyways because standard reference types can't be null (or at least, null is an error condition).
  • They might be doing null checks because it's a Nullable type, but they should be using Option types instead.
OK, but, if Unity is overloading ==, I'd expect the first two statements of the method to be (i) "is it null? return false" and (ii) "is it this? return true". Does Unity not do that because they think you shouldn't be doing null or identity checks in the first place, or that you should only use Object.ReferenceEquals? Or is the slow part even getting to the overloaded method in the first place?

Unity declares a type called `Object` and most classes in Unity derive from it. This is not the same as `System.Object`, and yes, reusing the name Object is unnecessarily confusing.

The problem with comparing Unity's object to null (aside from being slow), comes from the decision to return true when comparing a disposed object to null. In other words, if a comparison to null returns true, that means that either the compared object was actually null, or it wasn't null, but was disposed. This has always been an indefensible idea, but with more recent language additions it's become even dumber.

The null coalescing operator ( ?? ), null conditional operator ( ?. ), null pattern matching ( is null / is not null ), null cases in switch statements and nullable reference types all work based on strict null equality. So you can have an object that seemingly equates to null in Unity, but then get completely inconsistent results from any of those operators. This causes even more issues, because tools like Resharper will assume that no one would be so dumb as to return true when comparing a non null to null, so it will suggest converting this:
code:
if (x != null)
{
  x.DoSomething();
}
to this:
code:
x?.DoSomething();
Which should be the same thing, but isn't in Unity's case.

From what I remember, Unity petitioned Microsoft for changes to c# so that their hosed up version of null-ness would work with these newer features. Microsoft's response was basically "lol, no".

To be clear, Unity's "equal to null when disposed" idea was a terrible idea, even before these newer language features existed. E.g. the result of a null check can change without reassigning the variable that's being checked, something that would otherwise be completely impossible:
code:
bool b1 = x == null; // false
x.Dispose();
bool b2 = x == null; // true;
There's a bunch of other issues, but you get the idea.

chglcu
May 17, 2007

I'm so bored with the USA.

FlapYoJacks posted:

Serious question: Why would anybody choose Unity over Unreal? Is it simply a C++ vs C# thing? It also seems like Unity is cheaper as well vs royalties for UE yes?

In my experience, learning Unreal is a massive rear end-ache, and it feels very much designed for an experienced multi-discipline team, with the programmer experience worse than the experience for other disciplines. Unity is much easier to get started with, and it's very easy to do things as a programmer, with the other disciplines suffering a bit. Most of the problems with Unity don't really matter on the scale a lot of indies are working at. Also, for many people C++ vs C# is a big part of the decision. I personally dislike both engines quite a bit, but for different reasons.

Volte
Oct 4, 2004

woosh woosh
Unity is fine if you're already a software dev and can work on its level, but someone trying to learn programming with Unity is going to be at a massive disadvantage. It's a good balance of easy to use and powerful in the right hands, and there's a reason it's so ubiquitous among small teams. It's not great for the kinds of projects that Unreal excels at, like photorealistic environments and hugely complex asset management.

chglcu
May 17, 2007

I'm so bored with the USA.
Yeah, the ways Unity will bite you in the rear end would definitely suck for an inexperienced programmer. Unreal’s not especially newbie programmer friendly either, though, unless you stick to blueprints.

LongSack
Jan 17, 2003

LOOK I AM A TURTLE posted:

What does your code look like where you're having issues with the compiler thinking your DI dependencies are nullable? I must be missing something. Are you using constructor injection?

Yes, using constructor injection, and items that are injected are still flagged as possibly null by VS2022 even though i know that if they can’t be resolved there’s an exception thrown.

Interestingly, I have not come across the same situation when using minimal APIs and method injection.

Ranzear
Jul 25, 2013

Hammerite posted:

turn checked arithmetic on

Unity considers it normal behavior to not be checking, and so do I for shifted casts and doing weird bit twiddlng stuff that does come up in gamedev contexts, but the context was someone using float-to-int casts as a way to truncate which may have been compound horror. I always called it the NaN Plague in javascript, where everything at least stays NaN to make it obvious, but C# has the same NaN propagation issues and then this weird cast behavior can hide it.

checked as a block is neat though. I don't see it being too different from an overt NaN check, but it's something at least. There's a compiler directive to force it everywhere and apparently unchecked is a thing, which would be a much more verbose and intentional approach, but there claims to be some small performance penalty with it too (~5%).

I'm truly willing to admit my opinion of C# is entirely colored by Unity's bastardization of it, but to be fair it's also a classic Microsofting of some nice features with a lot of really bad features. Mono getting quietly bought up by MS through a half dozen umbrella transactions to kill the indie side of it is a red flag too. My personal opinion of C# is that it's the perfect language for people who don't know any better or care enough to be convinced why they should. It's the Charcoal Gray V8 SUV Daily Commuter of programming languages (and go figure the morning horde of those mostly take the SR 520 East exit).

Also, Godot adopting C# seemed like desperation to me, trying some 'how do you do fellow devs' to drag some attention over from Unity.

ExcessBLarg!
Sep 1, 2001

dwazegek posted:

The problem with comparing Unity's object to null (aside from being slow), comes from the decision to return true when comparing a disposed object to null.
Wait. Oh dear lord. That's what they're doing?

That should be illegal. Not like, illegal operation illegal, but someone should be in prison right now for this.

Volte
Oct 4, 2004

woosh woosh

ExcessBLarg! posted:

Wait. Oh dear lord. That's what they're doing?

That should be illegal. Not like, illegal operation illegal, but someone should be in prison right now for this.
It's not "disposed" in the C# sense but rather destroyed in the Unity Object sense. If you delete an object, then any reference to it becomes effectively null, but since C# doesn't actually support doing setting them to null, they had to modify what checking for null actually does so that it can check if the object is alive or not. In any case, the custom equality implementation short circuits if the reference you're checking actually is null. The performance penalty only happens if you're checking an object that's not actually null, but has been destroyed. If you want to ensure there's no performance penalty, just set your references to null when the objects are destroyed, which is what you'd have to do anyway.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
The performance penalty also happens when your object hasn't been destroyed. It's the checking whether the underlying native object has been destroyed that's slow - it's not like they do that check first and then only do something slow if it says yes.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Also they've managed to end up with an == implementation that isn't transitive, so that's really fun to have to reason about.

ExcessBLarg!
Sep 1, 2001

Volte posted:

If you delete an object, then any reference to it becomes effectively null,
It's still something that should be encoded in the C# object's state, not pretend null. It's one of those ideas that too "clever" and so actually problematic.

ExcessBLarg!
Sep 1, 2001
Quote != null.

CPColin
Sep 9, 2003

Big ol' smile.
Way to crash the forums

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

dwazegek posted:

From what I remember, Unity petitioned Microsoft for changes to c# so that their hosed up version of null-ness would work with these newer features. Microsoft's response was basically "lol, no".

Wait, so Unity uses C# but is not able (allowed? willing?) to make any changes to the compiler or language or runtime? That's so weird. Fork it you cowards.

Volte
Oct 4, 2004

woosh woosh

pokeyman posted:

Wait, so Unity uses C# but is not able (allowed? willing?) to make any changes to the compiler or language or runtime? That's so weird. Fork it you cowards.
They used to have their own Javascript-like scripting language but they replaced it with C#. Making their own bespoke version of C# that's not quite compatible with regular C# would be the worst of both worlds. The object null checking thing is just legacy baggage from way back in the day. For the most part supporting full, actual C# is a good thing and generally well implemented in my experience.

Jabor posted:

The performance penalty also happens when your object hasn't been destroyed. It's the checking whether the underlying native object has been destroyed that's slow - it's not like they do that check first and then only do something slow if it says yes.

Jabor posted:

Also they've managed to end up with an == implementation that isn't transitive, so that's really fun to have to reason about.
Both fair points (although I don't think anyone is doing any formal reasoning about Unity scripts), but I still think it's an overblown subject. There are a ton of things that can severely tank your performance in Unity, and you can build them right into the very fabric of your game from day one, requiring huge redesigns or refactors to fix them. This on the other hand, if it even causes a noticeable issue, will be easily found by the profiler and can be fixed more-or-less in place with very little impact. It's a quirk, every language and library has them, it's not worth saying that people should be killed in prison over it or whatever goons like to say when a language does something weird.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Volte posted:

Making their own bespoke version of C# that's not quite compatible with regular C# would be the worst of both worlds.

The post I quoted was describing how Unity null checks are not compatible with regular C#. Assuming it's accurate, Unity already made their own bespoke version. Maybe they should fix it instead of begging Microsoft.

Absurd Alhazred
Mar 27, 2010

by Athanatos
Unity made so many breaking changes in the past few years, why couldn't one of them have been "null checks that aren't an eldritch horror"?

Adbot
ADBOT LOVES YOU

BigPaddy
Jun 30, 2008

That night we performed the rite and opened the gate.
Halfway through, I went to fix us both a coke float.
By the time I got back, he'd gone insane.
Plus, he'd left the gate open and there was evil everywhere.


In His House at Unity Dead dead null check waits dreaming.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply