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
Volmarias
Dec 31, 2002

EMAIL... THE INTERNET... SEARCH ENGINES...

necrotic posted:

I have seen a payment processor that sends payment details (Cc and all) as an "image" request. This was last year.

You know someone was very disgusted but a little proud of doing that one

Adbot
ADBOT LOVES YOU

Tei
Feb 19, 2011

I could see somebody using a image submit button has a poor man anti-bot protection

JawnV6
Jul 4, 2004

So hot ...
I’m not sure I have a reasonable alternative but datetime objects coercing to false only if the lower order part is midnight UTC sounds pretty bad.

Soricidus
Oct 21, 2010
freedom-hating statist shill

JawnV6 posted:

I’m not sure I have a reasonable alternative but datetime objects coercing to false only if the lower order part is midnight UTC sounds pretty bad.

What’s unreasonable about the alternative of having strongly encapsulated types without surprising implicit conversion footguns?

Nostalgamus
Sep 28, 2010

code:
Catch ex As Exception
	Throw New Exception(ex.Message, ex)
why

Volguus
Mar 3, 2009

Nostalgamus posted:

code:
Catch ex As Exception
	Throw New Exception(ex.Message, ex)
why

There are good reasons to wrap exceptions and just rethrow them, but this ... no, has no place. Maybe that was the intention and just the author never got around to it.

Surprise T Rex
Apr 9, 2008

Dinosaur Gum

Nostalgamus posted:

code:
Catch ex As Exception
	Throw New Exception(ex.Message, ex)
why

old exception seemed dirty, want a new one

Volte
Oct 4, 2004

woosh woosh
There is something to be said for not allowing exceptions from internal systems to leak outside of a public API (flashbacks to having to deal with JSON.NET exceptions coming from inside a document database that didn't even use JSON externally), but just throwing a plain Exception shouldn't even be allowed. It should be an abstract type.

Hammerite
Mar 9, 2007

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

Volte posted:

There is something to be said for not allowing exceptions from internal systems to leak outside of a public API (flashbacks to having to deal with JSON.NET exceptions coming from inside a document database that didn't even use JSON externally), but just throwing a plain Exception shouldn't even be allowed. It should be an abstract type.

There's a pattern I use when I want to write extension methods for an enum:

code:
namespace ns
{
    public enum MyEnum
    {
        X,
        Y,
        Z,
    }

    public static class MyEnumExtensions
    {
        public static string SomeString(this MyEnum e)
        {
            switch (e)
            {
                case X: return "A";
                case Y: return "B";
                case Z: return "C";
                default:
                    throw new Exception($@"Unhandled {nameof(MyEnum)} ""{e}"" in switch");
            }
        }
    }
}
I always throw Exception in the default branch of the switch. What's the correct exception type to throw, then, if you think Exception should literally never be thrown?

note: SomeString() is intended to never throw for members of the enum, so ArgumentException would be inappropriate. The default branch is there because C# requires it, but it should only throw if the enum is updated with a new value and the switch isn't updated. (Yes it will also throw if the user does, say, ((MyEnum)(int.MinValue)).SomeString() - I don't care, that's their stupid fault if they do that)

Volte
Oct 4, 2004

woosh woosh
ArgumentException seems okay to me. Maybe ArgumentOutOfRangeException. It's generally considered bad practice to catch Exception other than in a top-level wrapper to log errors and handle them gracefully, so as a corollary, it should also be considered bad practice to throw an exception that it's bad practice to catch. If it's an exception that's not really intended to be handled and is just there as a way to force a bad code path to terminate, then InvalidOperationException is a fairly good catch-all.

The MSDN page on it has some rules of thumb.

SirViver
Oct 22, 2008
I'd use either of those: NotSupportedException, NotImplementedException, InvalidOperationException

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
ArgumentException, NotSupportedException, NotImplementedException, InvalidOperationException all imply to client code that it's their fault. It's not. It's my fault - my code was meant to handle all enum members, and I hosed up.

Ola
Jul 19, 2004

MyFaultButYourProblemException

b0lt
Apr 29, 2005

Hammerite posted:

There's a pattern I use when I want to write extension methods for an enum:

code:
namespace ns
{
    public enum MyEnum
    {
        X,
        Y,
        Z,
    }

    public static class MyEnumExtensions
    {
        public static string SomeString(this MyEnum e)
        {
            switch (e)
            {
                case X: return "A";
                case Y: return "B";
                case Z: return "C";
                default:
                    throw new Exception($@"Unhandled {nameof(MyEnum)} ""{e}"" in switch");
            }
        }
    }
}
I always throw Exception in the default branch of the switch. What's the correct exception type to throw, then, if you think Exception should literally never be thrown?

note: SomeString() is intended to never throw for members of the enum, so ArgumentException would be inappropriate. The default branch is there because C# requires it, but it should only throw if the enum is updated with a new value and the switch isn't updated. (Yes it will also throw if the user does, say, ((MyEnum)(int.MinValue)).SomeString() - I don't care, that's their stupid fault if they do that)

The correct option is to move the throw out of the switch so you get a compile time check that you actually did enumerate all of the enumeration values.

NotImplementedException would be the best, IMO. It's not the client's fault that your library doesn't implement something, the implication is that the goal is that that behavior will be supported at some point (or else it would be NotSupported or ArgumentOutOfRange).

CPColin
Sep 9, 2003

Big ol' smile.

b0lt posted:

The correct option is to move the throw out of the switch so you get a compile time check that you actually did enumerate all of the enumeration values.

:hai:

I had to add that as a rule in our coding standards, back when I was an architect and in charge of such things. People kept adding default cases and switches would start breaking at runtime when other people would add new enum values. (We had a shitload of enums for things.) I think the rule said you could only add a default case if a test existed that did a foreach over every possible value (which was another ongoing struggle).

Hammerite
Mar 9, 2007

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

b0lt posted:

The correct option is to move the throw out of the switch so you get a compile time check that you actually did enumerate all of the enumeration values.

It makes no difference whether the throw is in the switch or not.

b0lt
Apr 29, 2005

Hammerite posted:

It makes no difference whether the throw is in the switch or not.

Yes, it does, because it lets you delete the default case.

Hammerite
Mar 9, 2007

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

b0lt posted:

Yes, it does, because it lets you delete the default case.

so what?

All of these are equivalent, it makes no difference which you use

code:
public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
        default: throw new Exception();
    }
}

public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
        default: break;
    }
    throw new Exception();
}

public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
    }
    throw new Exception();
}
The presence or absence of a default case in the switch makes no difference, so long as the C# compiler can statically determine that every code path hits either a return statement or an uncaught exception. They all do the same thing.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Hammerite posted:

so what?

All of these are equivalent, it makes no difference which you use

code:
public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
        default: throw new Exception();
    }
}

public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
        default: break;
    }
    throw new Exception();
}

public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
    }
    throw new Exception();
}
The presence or absence of a default case in the switch makes no difference, so long as the C# compiler can statically determine that every code path hits either a return statement or an uncaught exception. They all do the same thing.

The value of a switch is having the compiler tell you what to update when you add a new case. In the first two examples, adding MyEnum.NewValue will not result in a compiler error, and you may not realize you need to handle a new case. In the last example, you'll get an error.

more falafel please
Feb 26, 2005

forums poster

Hammerite posted:

so what?

All of these are equivalent, it makes no difference which you use

code:
public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
        default: throw new Exception();
    }
}

public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
        default: break;
    }
    throw new Exception();
}

public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
    }
    throw new Exception();
}
The presence or absence of a default case in the switch makes no difference, so long as the C# compiler can statically determine that every code path hits either a return statement or an uncaught exception. They all do the same thing.

I'm not a C# expert so I don't know off the top of my head if it does it by default, but in the last case, the compiler can determine that the switch doesn't handle all cases, and throw a warning/error. Not handling all cases is a cause of lots of bugs.

ultrafilter
Aug 23, 2007

It's okay if you have any questions.




I don't have a good answer for this one.

(Yes, it's real.)

Hammerite
Mar 9, 2007

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

pokeyman posted:

... In the last example, you'll get an error.

No you won't. I've got the code sitting in front of me in VS. It builds just fine.

more falafel please posted:

... in the last case, the compiler can determine that the switch doesn't handle all cases, and throw a warning/error.

No it can't. Firstly, it's not an error in C# for a switch to not handle all cases; if none of the cases match and there's no default case, then execution skips the switch block entirely (aside from evaluating the switch-value). Secondly, a C# enum value can take any value from the underlying integer type, even if it isn't a named member of the enum; so handling all named enum members won't satisfy the compiler that all code paths terminate. There could in principle exist a compiler warning that is generated if a switch on an enum value doesn't have case-labels addressing all named members of the enum, but no such warning is implemented in the standard toolset so far as I am aware (how would it handle flag enums?)

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Hammerite posted:

No you won't. I've got the code sitting in front of me in VS. It builds just fine.


No it can't. Firstly, it's not an error in C# for a switch to not handle all cases; if none of the cases match and there's no default case, then execution skips the switch block entirely (aside from evaluating the switch-value). Secondly, a C# enum value can take any value from the underlying integer type, even if it isn't a named member of the enum; so handling all named enum members won't satisfy the compiler that all code paths terminate. There could in principle exist a compiler warning that is generated if a switch on an enum value doesn't have case-labels addressing all named members of the enum, but no such warning is implemented in the standard toolset so far as I am aware (how would it handle flag enums?)

Huh. Is there at least a linter rule you can turn on or something? It's a pretty useful feature of switch statements in other languages.

Flag enums could work as an exhaustiveness check on valid bit patterns, or just do nothing I guess.

CPColin
Sep 9, 2003

Big ol' smile.
lol C# sucks

ultrafilter posted:



I don't have a good answer for this one.

(Yes, it's real.)

It's definitely a battle: https://www.gocomics.com/calvinandhobbes/1990/09/26

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

ultrafilter posted:



I don't have a good answer for this one.

(Yes, it's real.)

one of the big problems with the western education model is that it tries to encourage people to come up with their own ideas, and present them. you would never hear something this loving stupid in a chinese classroom.

OddObserver
Apr 3, 2009

pokeyman posted:

Huh. Is there at least a linter rule you can turn on or something? It's a pretty useful feature of switch statements in other languages.

Flag enums could work as an exhaustiveness check on valid bit patterns, or just do nothing I guess.

I don't think people normally use switches on flag enums?

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

OddObserver posted:

I don't think people normally use switches on flag enums?

Probably not, but making C# switches useful would have to consider how it works.

b0lt
Apr 29, 2005

Hammerite posted:

No you won't. I've got the code sitting in front of me in VS. It builds just fine.


No it can't. Firstly, it's not an error in C# for a switch to not handle all cases; if none of the cases match and there's no default case, then execution skips the switch block entirely (aside from evaluating the switch-value). Secondly, a C# enum value can take any value from the underlying integer type, even if it isn't a named member of the enum; so handling all named enum members won't satisfy the compiler that all code paths terminate. There could in principle exist a compiler warning that is generated if a switch on an enum value doesn't have case-labels addressing all named members of the enum, but no such warning is implemented in the standard toolset so far as I am aware (how would it handle flag enums?)

Huh. Condolences on your defective language, I guess that's why everyone uses resharper.

It looks like C# 8's pattern matching (which uses the switch keyword) adds the warning for this, and also changes the behavior to throw if none of the switch arms match.

Ola
Jul 19, 2004

It's one of the things I really like with functional languages like Elm and F#. If you add a case to a discriminated union for instance, the compiler tells you all the match expressions where you need to add handling for it. It makes it pretty easy to add or remove stuff from big and complicated code bases.

Xarn
Jun 26, 2015

Hammerite posted:

No you won't. I've got the code sitting in front of me in VS. It builds just fine.


No it can't. Firstly, it's not an error in C# for a switch to not handle all cases; if none of the cases match and there's no default case, then execution skips the switch block entirely (aside from evaluating the switch-value). Secondly, a C# enum value can take any value from the underlying integer type, even if it isn't a named member of the enum; so handling all named enum members won't satisfy the compiler that all code paths terminate. There could in principle exist a compiler warning that is generated if a switch on an enum value doesn't have case-labels addressing all named members of the enum, but no such warning is implemented in the standard toolset so far as I am aware (how would it handle flag enums?)

Congratulations, your modern language handles enums even worse than C++ :v:

rarbatrol
Apr 17, 2011

Hurt//maim//kill.
I'm positive there are analyzers you can add that would enforce that at compile time. I've actually had .net builds fail for that reason (though I can't remember if it was VB or C# at this point) in the past, so I guess we added more rules at some point.

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

Ola posted:

It's one of the things I really like with functional languages like Elm and F#. If you add a case to a discriminated union for instance, the compiler tells you all the match expressions where you need to add handling for it. It makes it pretty easy to add or remove stuff from big and complicated code bases.

Yeah I was going to say this, it's one of the things that those languages handle really well. Especially compared to the C-style switch syntax that so many languages have adopted, which I've never liked.

Tei
Feb 19, 2011

ultrafilter posted:



I don't have a good answer for this one.

(Yes, it's real.)

This is wrong.

Jesus was not cruxified in a +, he was cruxified in a X.

https://en.wikipedia.org/wiki/Tripalium

Has what + means in C++. Whatever you want, ... the language let you overload the operator.


code:
    point operator+ (const point & first) const
    {
        printf("If God is good, why he created Evil?\n");

        return point(x + first.x, y + first.y);
    }

Tei fucked around with this message at 20:19 on Feb 12, 2021

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Hammerite posted:


code:
public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
    }
    throw new Exception();
}
The presence or absence of a default case in the switch makes no difference, so long as the C# compiler can statically determine that every code path hits either a return statement or an uncaught exception. They all do the same thing.

Here, I fixed it:
code:
public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
    }
}
In that that will not compile unless X is the only member of the enum.

Hammerite
Mar 9, 2007

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

Munkeymon posted:

Here, I fixed it:
code:
public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
    }
}
In that that will not compile unless X is the only member of the enum.



That doesn't compile at all; not even if X is the only member of the enum. I've explained this in previous posts

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Hammerite posted:

That doesn't compile at all; not even if X is the only member of the enum. I've explained this in previous posts

Huh, my bad - could have sworn that worked but you can do

code:
void Main() {
	E e = (E)2;
	f(e).Dump();
}

enum E {
	A,
}

string f(E e){
	switch(e){
		case E.A: return "A";
	}
	return string.Empty;
}
and the compiler is fine with it, so that's probably why. Presumably so that a code could gracefully handle deserializing an enum from a newer version with more enum values.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Tei posted:

This is wrong.

Jesus was not cruxified in a +, he was cruxified in a X.

https://en.wikipedia.org/wiki/Tripalium

There is indeed controversy about the form of the cross, but it’s about whether there was a crossbar and (if so) whether it was tied to the top of the post or (as tradition has it) merely nearly the top. I’ve never seen anything suggesting it was a tripalium before.

dwazegek
Feb 11, 2005

WE CAN USE THIS :byodood:

Munkeymon posted:

Huh, my bad - could have sworn that worked but you can do

code:
void Main() {
	E e = (E)2;
	f(e).Dump();
}

enum E {
	A,
}

string f(E e){
	switch(e){
		case E.A: return "A";
	}
	return string.Empty;
}
and the compiler is fine with it, so that's probably why. Presumably so that a code could gracefully handle deserializing an enum from a newer version with more enum values.

Except that that's really not any different from these earlier examples that Hammerite posted (aside from using a return rather than a throw):
code:
public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
        default: throw new Exception();
    }
}

public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
        default: break;
    }
    throw new Exception();
}

public static string SomeString(this MyEnum e)
{
    switch (e)
    {
        case MyEnum.X: return "A";
    }
    throw new Exception();
}
In C# all enums are always backed by an integer type, the default being Int32, so any values that the integer type can represent, are also possible for the enum type. So, unless you're covering all 4 billion possibilities, the switch statement isn't exhaustive, and thus needs a default case, or the code will just fall through the switch, and you need a return/throw after it.

Even if you use an exhaustive pattern matching switch, the compiler rarely seems to handle that specific case, because it hardly ever comes up. E.g. this also doesn't compile:
code:
	public static string Blah(int i)
	{
		switch (i)
		{
			case int n when n < 0: return "";
			case int n when n >= 0: return "";
		}
	}
Even the newer switch expressions, which do let you omit the default case, simply auto-generates one for you if you do so.

Stupid side note, switching on a boolean has changed sometime between the last .NET Framework release and .NET5. In .NET5 (and possible older core versions as well), this compiles:
code:
	public static string Blah(bool b)
	{
		switch (b)
		{
			case true: return "T";
			case false: return "F";
		}
	}
In .NET Framework it doesn't. This used to be a weird edge case, because the switch statement would only match the "true" case if the boolean actually had binary value 0x01, so if you marshalled a non 0x00/0x01 value to a boolean, it wouldn't match any case statements. Which also means that the switch statement is not exhaustive, as it only covers 2 out of the possible 256 values.

I guess they finally decided to fix this weird issue in core at some point. Granted, it was never much of an issue, as there's little to no reason to switch on a boolean.

dwazegek fucked around with this message at 22:05 on Feb 12, 2021

dwazegek
Feb 11, 2005

WE CAN USE THIS :byodood:

Hammerite posted:

ArgumentException, NotSupportedException, NotImplementedException, InvalidOperationException all imply to client code that it's their fault. It's not. It's my fault - my code was meant to handle all enum members, and I hosed up.

If someone casts an integer value that doesn't exist in the enum, then it definitely is their fault, so an ArgumentOutOfRangeException is applicable.

I guess you could first check for Enum.IsDefined, and throw ArgumentOutOfRangeException in that case and a different exception in the default case of your switch. But even then you should just define your own exception type, and not throw Exception.

Adbot
ADBOT LOVES YOU

Kilson
Jan 16, 2003

I EAT LITTLE CHILDREN FOR BREAKFAST !!11!!1!!!!111!

dwazegek posted:

Stupid side note, switching on a boolean has changed sometime between the last .NET Framework release and .NET5. In .NET5 (and possible older core versions as well), this compiles:
code:
	public static string Blah(bool b)
	{
		switch (b)
		{
			case true: return "T";
			case false: return "F";
		}
	}
In .NET Framework it doesn't. This used to be a weird edge case, because the switch statement would only match the "true" case if the boolean actually had binary value 0x01, so if you marshalled a non 0x00/0x01 value to a boolean, it wouldn't match any case statements. Which also means that the switch statement is not exhaustive, as it only covers 2 out of the possible 256 values.

Everyone knows booleans have 3 values: True, False, and FileNotFound

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