• dpm (unregistered)

    In an extremely rude approach to TDWTF, I have actually learned something from today's article. I humbly apologize for not ridiculing the code presented, but I've been writing .NET applications since 2008 (and being paid to do so!) but did not know about this.

  • NotAThingThatHappens (unregistered)

    I have a reading disorder which puts me in the lower 25% considering reading speed. The less I have to read, the better.

    So you might want to look at these extensions in a broader light: working with strings is kind of horrible is C#, where string comparison is Case-sensitive by default.

    //// compare two strings ignoring case var isEqual = string.Equals(LengthyStringName, OtherStringName, StringComparison.OrdinalIgnoreCase); var isEqual2 = LengthyStringName.Equals(OtherStringName, StringComparison.OrdinalIgnoreCase);

    //// Now implemented with an extension method just like in the article: var isEqual = LengthyStringName.EqualsIgnorecase(OtherStringName);

    Now I have less to read and I already know it is case-insensitive halfway through. Once you go down the path of using extension methods to improving readability by removing superfluous words such as 'string.' and 'StringComparison.OrdinalIgnoreCase', it is quite easy to reach the point where you create an extension method just like in the article.

    I have these exact extension methods (and I feel attacked, lol),. Instead of 'IsNotNullOrEmpty' I use 'HasValue', again, reading disorder, the method names should not look too much like each other.

  • Nothing to see here (unregistered)

    There's no WTF here, these two extensions are part of every utils library since the .NET dinosaurs roamed the earth. They're neat, they're useful, they improve readability and there is no mystery here: the string class is "nullable" by definition and extension methods can be called on null, also by definition (since they must be defined in a static class).

  • Jam (unregistered)

    Meh, I don't know if this is WTF tbh, seems perfectly reasonable to me.

  • MaxiTB (unregistered)

    The best practice pattern for extension methods is to always throw a NullReferenceException() when the instance is null. So this code is already going against design principles for extension methods.

    Additonally behavior of string.IsNullOrEmpty() in context of non-nullable reference types and Roslyn check regarding it, is detailed in a bunch of dev logs and multiple discussions, similar to bool Try(out x) behavior. There is a ton to it in detail, especially when it comes to nullable ValueTypes, so that is another bag of beans.

    I did this myself in the past (because I was dumb and lazy, aka I didn't read up on best practices), it's stupid, I figured out by doing that it's a bad idea in practice in general to introduce non-expected behavior via extensions, by allowing instances without an object. In short it's a classical Pandoras box, it is going to hurt long down the road and you should never introduce special behavior that goes against expected one.

  • justJanne (unregistered)

    Funnily, this method has exactly the signature of what Kotlin (on the JVM) offers. Its stdlib contains an "isNullOrEmpty" function that works on nullable receivers and just calls the actual implementation just like this code does.

    https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/is-null-or-empty.html

  • (nodebb) in reply to MaxiTB

    it's a bad idea in practice in general to introduce non-expected behavior via extensions

    It's a bad idea to introduce non-expected behaviour no matter how you do it. POLA (1) is valuable everywhere.

    (1) Principle Of Least Astonishment, i.e. do the thing that is the least surprising possible.

  • RLB (unregistered)

    TRWTF is not being able to call a function called isNullOrEmpty on null. Call is isEmpty, then!

  • Brian (unregistered) in reply to MaxiTB
    The best practice pattern for extension methods is to always throw a NullReferenceException() when the instance is null. So this code is already going against design principles for extension methods.

    "Best practice" doesn't mean "only practice". If your method literally has a null check right in the name, it's not really that surprising that it's not going to throw an exception on null. But if it makes you feel better, then sure, write "foo?.IsEmpty() ?? true" everywhere instead. Or, you know, just don't use extension methods ;)

  • Daniel (unregistered)

    As long as the method you call is not virtual and you're not using any members there is nothing that hinders you to call a method on a null-object. (Code like "if (this == null) {}" definitely looks strange, but I've seen such stuff before.

    The main problem with this kind of code is that you're not expected to call any functions on a null-object. So I'd call it a code smell...

  • John Melville (unregistered)

    Longtime C# coder (since version 1 here.)

    I have written these extension methods (almost character for character) and they exist in multiple mainstream C# libraries, as noted above.

    Odd quirk of the language that there are some methods you can call on null, sure. Extremely useful in some circustances, yes. WTF? I don't think so.

  • NotAThingThatHappens (unregistered)

    Only related to calling methods on null objects, not every null is the same as the other.

    In C# var toString = (null as dateTime?).ToShortDateString(); // crash

    var interpolatedString = ${"(null as dateTime?).ToShortDateString()}"; // empty string

  • Canthros (unregistered)

    It's been my experience in C# that instance methods cannot be invoked on a null reference: it always throws a NullReferenceException in this language. (C++ was different, but it's been a long time since I dealt with C++, and this WTF was explicitly a C# thing.) Extension methods in C# are always static, but there's some syntactic sugar to let the programmer invoke them like instance methods.

    As commentary on the article, though, extension methods post-date the System.Nullable<T> type that underlies nullable value types, but pre-dates the confusingly-named 'nullable reference types' feature by several years.

  • Tom (unregistered)

    Not a WTF. I frequently introduce the exact same method in my projects, just because it's less typing to write s.IsNullOrEmpty() than string.IsNullOrEmpty(s).

  • Mr Bits (unregistered)

    The author of that code must have gotten bored with the IOCCC and moved on to C#.

  • (nodebb) in reply to Daniel

    Perhaps, but it makes my teeth itch to see that sort of thing, especially since my background is C++, where calling methods on NULL (or nullptr) pointers is UB.

  • Richard Brantley (unregistered)

    I wouldn't do this because the BCL already provides for this function, and introducing a wrapper around it just makes other developers scratch their heads and wonder why. Our IDEs are certainly good enough that typing string.IsNullOrEmpty(somestring) is not more difficult that typing somestring.IsNullOrEmpty(). And I would certainly expect to see !string.IsNullOrEmpty(somestring) than somestring.IsNotNullOrEmpty(); I would argue seeing the negator in the expression is more clear that distinguising the presence of Not in the method name. It's the kind of thing someone scanning the code could easily miss.

  • nope (unregistered)

    guilty of that one myself.

    it's not "clean", i grant you that - but it makes the rest of the code cleaner and easier to read.

    and given that the name is very clear about what it does, there shouldn't be any actual confusion about why this doesn't throw a NullException when called on null. so i'd say the benefits far outweigh the drawbacks.

  • Loren Pechtel (unregistered)

    Add me to those who have no problem with this.

    The name explicitly expects nulls, calling it on a null is not a WTF.

    Strings are a special case, you have both null and empty which realistically mean the same thing in most cases. Having a function that tests for either makes a lot of sense.

  • VI (unregistered)

    A similar approach in Golang is actually encouraged: methods with nullable receivers (interfaces and pointers) are encouraged to handle the case of this == nil, because that's a possible (and therefore valid) value.

  • (nodebb) in reply to MaxiTB

    Some best practices are best ignored.

  • (nodebb) in reply to Steve_The_Cynic

    There is nothing unexpected about the behaviour of s.IsNullOrEmpty(). The only thing unexpected is that it can be made to work and even that only if you both care and do not know about extension methods. So yes, if you are a curious fellow you'll check how it's done, but you are definitely not going to be surprised by WHAT it does.

  • Your Name (unregistered)

    My favourite pattern is to ignore people that harp on patterns.

    It's useful, increases readability and therefore in wide use. Not a WTF.

  • Chris (unregistered)

    I agree that the extension method itself is not a WTF, as it is in wide use for good reason (I just checked our codebase, and yep, it's there). But being able to call what looks like an instance method on a null is a WTF, since that's a weird quirk relating to how extension methods are implemented, and not what you can normally do in C#.

    If you weren't thinking deeply about it, or weren't aware, then you might expect that the compiler somehow adds the extension method as an instance method to the class. They don't do that, for what I'm sure are practical reasons, but if they did, then this wouldn't be possible. I doubt they did it this way just to allow users to call instance methods on null.

  • MaxiTB (unregistered) in reply to NotAThingThatHappens

    Ehm yeah, because the compiler is already optimizing the string concatination by removing all null without checking the full string. After all, string.Format(string firmat, params object?[] args) always allowed for null for legacy reasons because non-nullablebreference types were not a thing before .net 5 ;-)

  • Sole Purpose Of Visit (unregistered) in reply to Jenda

    The unexpected thing is what happens everywhere else in the codebase where a method is called on a null receiver. I've actually been bitten by this myself. "Why" I asked myself "can I call this method on a null, but not [I}that[/I] method? Am I doing the right thing? The wrong thing? A schroendinger's cat thing?"

    Count me in on the "I learned something from today's WTF."

    The OP may not violate POLA, but it definitely creates a sense of dread and unease. Consistent behaviour across a class is also a good thing.

  • Jim Jam (unregistered)

    Boolean algebra suggests that !IsNullOrEmpty is not the same as IsNotNullOrEmpty but rather IsNotNullAndNotEmpty

  • Jim Jam (unregistered)

    Because extension methods are legitimate for null values, in our project we have a handy method IEnumerable<T> OrEmpty<T>(this IEnumerable<T> source) for sanitazing inputs from nulls where collections are expected. Alternatives would be much more verbose. Not a WTF.

  • jakirofire (unregistered)

    I think the wtf here is that doing the above (even if others find it acceptable) is breaking the convention that if something is null, that you shouldn't be able to do anything with it. With the whole null-able system being introduced and people being encouraged to test if something is null before it's used (which I think generally a good thing), this sort of code might reduce readability by confusing already known names with functionality that is not exactly the same.

  • Mike Rosoft (unregistered)

    Besides, you can do the following:

    int? foo=null;

    if(foo.HasValue) { DoSomething(foo.Value) }

    How is that different from creating an extension method and calling:

    string foo = null; //string is a reference type and so it can be null

    if(!foo.IsNullOrEmpty()) { DoSomething(foo) }

  • codecarrots (unregistered)

    informative https://codecarrots.com/

  • (nodebb) in reply to jakirofire

    That's a pretty dumb convention.

  • (nodebb) in reply to Chris

    You would be right in case of virtual methods. Those do need to be added to a table that exists at runtime and do need an actual instance so that you could call the right one for that instance. There is no technical reason non-virtual methods couldn't be called on nulls and in many cases it'd simplify the code.

  • james davis (unregistered)

    Crypto Recovery Services Crypto Recovery Services, Houston, TX. 1 talking about this. How to recover lost, stolen, hacked, forgotten and scammed crypto currencies from fraudulent investment platforms Website: www.cryptoreclaimfraud.com

  • PedanticRobot (unregistered)
    Comment held for moderation.
  • David Mårtensson (unregistered) in reply to Brian
    Comment held for moderation.

Leave a comment on “Extended and Empty”

Log In or post as a guest

Replying to comment #:

« Return to Article