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
JawnV6
Jul 4, 2004

So hot ...

Hammerite posted:

NB. I am aware that the above doesn't take account of fallthrough/goto-case, but a switch statement using these is equivalent to the if-else version if you add gotos in the appropriate places.
I think restricting the comparison to == is more limiting than literal values. Verilog has a much more expressive case structure. Casex/casez allow partial comparisons and priority is explicitly guaranteed so it's natural to see cases set up as '1XX, '01X, '000, '001. "Expressions" are allowed in the case list, although I can't recall seeing it used without a literal being passed in, the case is used to sort out which pattern is matched first.

Adbot
ADBOT LOVES YOU

ultramiraculous
Nov 12, 2003

"No..."
Grimey Drawer

b0lt posted:

Literally everything PHP does is a bad choice

Yup.

Hammerite
Mar 9, 2007

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

JawnV6 posted:

I think restricting the comparison to == is more limiting than literal values.

This is reasonable. I see functional languages' pattern-matching feature praised a lot (mostly by people who really like functional languages, but still). But I haven't used hardcore functional languages so I don't really have experience enough to like/dislike it.

One could imagine a sort of "generalised switch" statement that takes two arguments, a comparison function and an operand. The basic switch statement being the generalised one in the case where the comparison function is a test for equality.

In the case of PHP specifically the usefulness of its switch statement must I imagine be impacted by the fact it uses == and not ===

b0lt posted:

Literally everything PHP does that differs from the mainstream is a bad choice

The "arbitrary expressions in case labels in a switch statement" behaviour and the "continue is meaningful in a switch statement" behaviour are both in my view good choices, for reasons I have explained in previous posts. If you would argue that either is a bad choice because it will surprise people who are used to the way other languages do things, then that's a reasonable position to hold, but in order to be consistent you need to apply the same pessimism to any decision made by any other language that goes against the grain.

If on the other hand you're just posting to bash PHP because PHP is in general terrible, that's fine too, but I see no reason to regard the rare good idea that PHP throws out (maybe by accident or in a "stopped clock is right twice a day" fashion) as "poisoned" just because it's associated with PHP. That's not the way reasonable people evaluate ideas.

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.

Hammerite posted:

The "arbitrary expressions in case labels in a switch statement" behaviour and the "continue is meaningful in a switch statement" behaviour are both in my view good choices, for reasons I have explained in previous posts. If you would argue that either is a bad choice because it will surprise people who are used to the way other languages do things, then that's a reasonable position to hold, but in order to be consistent you need to apply the same pessimism to any decision made by any other language that goes against the grain.

The reason I'm not a big fan of switch statements with conditionals is that semantically, the switch operator is meaningless if you're providing a list of expressions for cases.

To demonstrate, here is how to get a switch statement to work in javascript using expressions....

quote:

// switch on amount
switch (true) {
case (amount >= 7500 && amount < 10000):
//code
break;
case (amount >= 10000 && amount < 15000):
//code
break;
//etc...

Why bother?

raminasi
Jan 25, 2005

a last drink with no ice

Hammerite posted:

One could imagine a sort of "generalised switch" statement that takes two arguments, a comparison function and an operand. The basic switch statement being the generalised one in the case where the comparison function is a test for equality.

F# does (basically) this and it's pretty great

gonadic io
Feb 16, 2011

>>=
Pattern matching is the best, yeah

gonadic io fucked around with this message at 22:15 on Jul 4, 2015

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Hammerite posted:

One could imagine a sort of "generalised switch" statement that takes two arguments, a comparison function and an operand.

So basically condp.

Captain Capacitor
Jan 21, 2008

The code you say?
match thing with
| Some x -> x
| None -> ()

Soricidus
Oct 21, 2010
freedom-hating statist shill

Captain Capacitor posted:

match thing with
| Some x -> x
| None -> ()

Seriously gently caress every language designer who has ever included null after this was invented

Milotic
Mar 4, 2009

9CL apologist
Slippery Tilde

Soricidus posted:

Seriously gently caress every language designer who has ever included null after this was invented

I'm possibly missing some subtlety above, but null is useful in imperative based programming languages where you don't know what the value of a variable to be assigned will be yet, and it doesn't have a sensible default value. It also fulfills the useful requirement of failing hard and fast when one arises unexpectedly - it means you've got a logic error or a failure to respect the interface of a method call. I think most .NET programmers wouldn't mind as much if the null reference exception just listed the variable name somehow (or if the runtime was able to infer the type the object was meant to be).

e: I guess you're encoding that it can return a unit in the signature of the method, which could be useful - but isn't unit in danger of becoming a bucket type like null then? i.e. It's undefined, or the method does something under the covers.

Milotic fucked around with this message at 10:27 on Jul 5, 2015

Destroyenator
Dec 27, 2004

Don't ask me lady, I live in beer
PHP just doesn't go far enough IMO.

https://en.wikipedia.org/wiki/Guarded_Command_Language posted:

The selection (often called the "conditional statement" or "if statement") is a list of guarded commands, of which one is chosen to execute. If more than one guard is true, one statement is nondeterministically chosen to be executed. If none of the guards are true, the result is undefined.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Milotic posted:

I'm possibly missing some subtlety above, but null is useful in imperative based programming languages where you don't know what the value of a variable to be assigned will be yet, and it doesn't have a sensible default value.
Not initializing the variable is a perfectly acceptable option here. Your compiler should be able to work out if the variable is definitively initialized before use in all execution paths.

quote:

It also fulfills the useful requirement of failing hard and fast when one arises unexpectedly - it means you've got a logic error or a failure to respect the interface of a method call. I think most .NET programmers wouldn't mind as much if the null reference exception just listed the variable name somehow (or if the runtime was able to infer the type the object was meant to be).
Wouldn't it be better if the compiler could catch that you weren't respecting the interface of a method call?

quote:

e: I guess you're encoding that it can return a unit in the signature of the method, which could be useful - but isn't unit in danger of becoming a bucket type like null then? i.e. It's undefined, or the method does something under the covers.

If it's encoded in the signature of the method and I have to unwrap it explicitly (like returning a Maybe or an Either) then it's obvious from the caller side that I have to handle both cases.

When null is allowed by default it is terrible because every method that returns an object could be returning null. Maybe this one returns null on error! Maybe it throws an exception! We just don't know.

Eric Lippert has said that he wishes .NET had non-nullable references by default. But now it's too late.

Null is not a good idea. The "problems" it "solves" either don't really exist or have much better solutions.

Soricidus
Oct 21, 2010
freedom-hating statist shill
The point is that "a variable that may or may not have been assigned any useful value" is a bad thing and a regular source of bugs, and having null as a regular value means literally any variable can be in that state without warning.

Option types in languages without null mean that the default is for it to be safe to assume that a variable has a value, and in the cases where there's a good reason for that not to be the case, that's explicitly stated in such a way that trivial static analysis can detect whether the code is going to handle that case.

Algebraic data types and pattern matching mean that things like option types can be handled relatively nicely. Contrast the hideous syntax in Java's half-assed implementation.

Milotic
Mar 4, 2009

9CL apologist
Slippery Tilde

Dessert Rose posted:

Not initializing the variable is a perfectly acceptable option here. Your compiler should be able to work out if the variable is definitively initialized before use in all execution paths.

Within a method yes, but some times you really do need to return a null. e.g. A method that returns information on something in the real world - what's the address of this person. Oh it's not been added yet.

quote:

Wouldn't it be better if the compiler could catch that you weren't respecting the interface of a method call?

Yes, but it would likely not cover every edge case and possibly bloat compile times.

quote:

If it's encoded in the signature of the method and I have to unwrap it explicitly (like returning a Maybe or an Either) then it's obvious from the caller side that I have to handle both cases.
When null is allowed by default it is terrible because every method that returns an object could be returning null. Maybe this one returns null on error! Maybe it throws an exception! We just don't know.
Eric Lippert has said that he wishes .NET had non-nullable references by default. But now it's too late.
Null is not a good idea. The "problems" it "solves" either don't really exist or have much better solutions.

I definitely agree that returning a Maybe or Either forces you to handle it, but that can cause issues as well:

1) You use a 'railway orientated' approach and it ends up bubbling to the top anyway. Depending on the language, you have difficulty tracking it back to the place where it wrong. This is especially a problem in deeply nested systems. I've done something like this in systems built in C# which should avoid throwing exceptions, so they return an Attempt<T> object instead, and sometimes you do wish you had a stack trace at the point it first went wrong.
2) It forces you to make a decision there and then about what to do in order to get the program to compile, which you might not be able to make at the time. Or you might make the wrong one. Some systems benefit from crashing hard and fast when they run into edge cases like this.

I have to admit, of all the problems with C# (it's a great language but the .NET framework is bit wonky in places especially 1.0 apis), I don't personally rate null reference exceptions as that big of a problem. It's highly likely my experience has been coloured by the types of problems I've had to work on though. I've done a lot of work on build, test and monitoring systems in secure environments, so everything is terrible in a different way.

It would be interesting to see what falls out in terms of quirks and painpoints when you do start having ADTs and pattern matching in languages meant for LOB apps, where stuff is often a bit woolly, and you get edge cases for certain customers, accounts, geographic regions, time zones, whatever. (This is my chief concern with functional programming in particular - if you're trading 40 stock exchanges, they all differ in weird ways and at different points. Sometimes you just need to hack stuff).

I'd be quite happy with null staying in the language, but with language support for code contracts. Though even then that can lead to fun and games with polymorphism - inputs valid for one implementation aren't for another, but they all use the same interface since interfaces being injected in can be more descriptive than a general function call. (Func is great, but abused it can be as meaningless as Tuple<X,Y> vs a properly named class).

NihilCredo
Jun 6, 2011

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

quote:

1) You use a 'railway orientated' approach and it ends up bubbling to the top anyway. Depending on the language, you have difficulty tracking it back to the place where it wrong. This is especially a problem in deeply nested systems. I've done something like this in systems built in C# which should avoid throwing exceptions, so they return an Attempt<T> object instead, and sometimes you do wish you had a stack trace at the point it first went wrong.

You want to log or message the point where it went wrong anyway. In your example, if your FetchAddress() method finds that the address hasn't been added yet, you're going to want to show the user something like "Address not found!", and maybe also write in a log file some more specific information such as which particular query failed.

Also, if you've seen the same Railway Oriented Programming slides I have, then you know that you can just return a custom error type and know at the end of the railway where it is exactly that the failure happened, without need for exceptions or stack traces.

NihilCredo fucked around with this message at 12:25 on Jul 5, 2015

Vanadium
Jan 8, 2005

Not having null is great, but if this compiles...

Captain Capacitor posted:

match thing with
| Some x -> x
| None -> ()

... then your unit type is basically just null anyway (or x is () too).

Soricidus
Oct 21, 2010
freedom-hating statist shill

Milotic posted:

Within a method yes, but some times you really do need to return a null. e.g. A method that returns information on something in the real world - what's the address of this person. Oh it's not been added yet.
So you return an option type.

Milotic posted:

1) You use a 'railway orientated' approach and it ends up bubbling to the top anyway. Depending on the language, you have difficulty tracking it back to the place where it wrong. This is especially a problem in deeply nested systems.
So you throw an exception. There's nothing wrong with using exceptions if you have an exceptional error case to deal with, particularly something deeply nested. That's kind of what they're designed for.

If you also need to avoid exceptions, then you already have a problem and null doesn't help.

Milotic posted:

2) It forces you to make a decision there and then about what to do in order to get the program to compile, which you might not be able to make at the time. Or you might make the wrong one. Some systems benefit from crashing hard and fast when they run into edge cases like this.
So you use an access method that throws an exception if the option is None. Everything continues to work just like if you had null, except now it's explicit in your code that that's what you're doing, instead of being a hidden surprise for anyone who isn't intimately familiar with the codebase.

Jeb Bush 2012
Apr 4, 2007

A mathematician, like a painter or poet, is a maker of patterns. If his patterns are more permanent than theirs, it is because they are made with ideas.

Milotic posted:

Within a method yes, but some times you really do need to return a null. e.g. A method that returns information on something in the real world - what's the address of this person. Oh it's not been added yet.
Except the whole point here is that you (the language designer) can make this unnecessary by including option types instead!

Milotic posted:

I definitely agree that returning a Maybe or Either forces you to handle it, but that can cause issues as well:

1) You use a 'railway orientated' approach and it ends up bubbling to the top anyway. Depending on the language, you have difficulty tracking it back to the place where it wrong. This is especially a problem in deeply nested systems. I've done something like this in systems built in C# which should avoid throwing exceptions, so they return an Attempt<T> object instead, and sometimes you do wish you had a stack trace at the point it first went wrong.
2) It forces you to make a decision there and then about what to do in order to get the program to compile, which you might not be able to make at the time. Or you might make the wrong one. Some systems benefit from crashing hard and fast when they run into edge cases like this.

You need to do one of these with nullable types too, it's just that option types force you to be explicit about how you are handling it. (and if the best way of handling it is to fail with a stack trace immediately, you can do that!) Because nulls don't force you to be explicit about how they're handled, it's very easy to have the error show up in a weird place - maybe your null reference gets passed around for a while and it's only when a method actually ends up getting called on it that you get your stack trace.

e: Okay I got beaten pretty badly there. What Soricidus said. :v:

Jeb Bush 2012 fucked around with this message at 12:56 on Jul 5, 2015

NihilCredo
Jun 6, 2011

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

Vanadium posted:

Not having null is great, but if this compiles...


... then your unit type is basically just null anyway (or x is () too).

Option.None is conceptually much the same as null, yes. But the big difference is that every other method in the program can take a Some x as argument and the compiler will automatically guarantee that it won't be fed nulls, ever.

Whereas with nulls, you can never tell apart a variable that has been null-checked from one that hasn't, so you're forced to always null-check all your arguments anyway.

Vanadium
Jan 8, 2005

I'm talking about unit/(), not None here.

brap
Aug 23, 2004

Grimey Drawer
The whole point of the Option type is to make it so the compiler can require that you deal with a possibly missing value in a safe way. Once you get used to it, null will put a very sour taste in your mouth.

NihilCredo
Jun 6, 2011

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

Vanadium posted:

I'm talking about unit/(), not None here.

Ah, sorry. Yeah, that's a pretty poor pattern matching block; you're supposed to return the same type for every case, so either you return a x on both sides (i.e. for the None case you return a default value for x) or you return a unit on both sides (i.e. for the Some case, you do something with x and return unit). Returning a type that can be either unit or x is indeed just pushing the null-check downstream.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...

Milotic posted:

Yes, but it would likely not cover every edge case and possibly bloat compile times.

As to the latter: compile times are like the last thing I care about, compared to getting a crash report from production because of a nullref. I'll happily blow an hour a day on automated tools that tell me when I could be loving up.

Isn't the entire point of a managed language to help you not blow your foot off? That's what we're spending all those runtime resources on, right? If you don't want compiler warnings for every possible mistake in your code, why not just write native code?

As to the former: The point is not to cover every edge case, necessarily, but to make it very difficult to make this kind of mistake. It may be possible to "trick" the compiler one way or the other (usually managed compilers err on the side of, well, errors, if they can't figure things out) but that is a sign that you are doing something wrong too.

If a machine can't figure out your code's intent, you should probably restructure it.

KernelSlanders
May 27, 2013

Rogue operating systems on occasion spread lies and rumors about me.

Milotic posted:

2) It forces you to make a decision there and then about what to do in order to get the program to compile, which you might not be able to make at the time. Or you might make the wrong one. Some systems benefit from crashing hard and fast when they run into edge cases like this.

It doesn't really, and that's the point. Your method can simply return an Option as well, passing the lack-of-data error (which may or may not actually be an error, but let's assume it is for now) along to the caller. The difference is with an Option the caller of your method is explicitly told that it should expect the possibility of no returned value rather than you just knowing to handle the possible exception from the docs. If you really want your method to take a Class1 and return a Class2 rather than an Option of each, the caller can always lift your method to handle that case. That is what map is for after all.

Steve French
Sep 8, 2003

KernelSlanders posted:

It doesn't really, and that's the point. Your method can simply return an Option as well, passing the lack-of-data error (which may or may not actually be an error, but let's assume it is for now) along to the caller. The difference is with an Option the caller of your method is explicitly told that it should expect the possibility of no returned value rather than you just knowing to handle the possible exception from the docs. If you really want your method to take a Class1 and return a Class2 rather than an Option of each, the caller can always lift your method to handle that case. That is what map is for after all.

Passing back to the caller the lack of data (and exposing that possibility in your interface explicitly with the type system) *is* deciding what to do in that case.

Edit: I'm in agreement with you, to be clear.

TheresaJayne
Jul 1, 2011

NihilCredo posted:

You want to log or message the point where it went wrong anyway. In your example, if your FetchAddress() method finds that the address hasn't been added yet, you're going to want to show the user something like "Address not found!", and maybe also write in a log file some more specific information such as which particular query failed.

Also, if you've seen the same Railway Oriented Programming slides I have, then you know that you can just return a custom error type and know at the end of the railway where it is exactly that the failure happened, without need for exceptions or stack traces.

or just return a NoAddress() object.

sarehu
Apr 20, 2007

(call/cc call/cc)
null is seriously the most overrated "problem" ever. If you just pretend they don't exist, that a pointer in null state is just a trap representation that you can never read or compare to anything, i.e. that the nullness of a pointer is something you know statically, then you won't get any big costly problems in your software development (and certainly some non-nullable reference type being the default would be worse).

Volte
Oct 4, 2004

woosh woosh

sarehu posted:

null is seriously the most overrated "problem" ever. If you just pretend they don't exist, that a pointer in null state is just a trap representation that you can never read or compare to anything, i.e. that the nullness of a pointer is something you know statically, then you won't get any big costly problems in your software development (and certainly some non-nullable reference type being the default would be worse).
What happens when the libraries you call don't pretend that

KaneTW
Dec 2, 2011

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

I dunno, if the volume of posts about null is anything to go by, null is the most serious problem since...Y2K!

Doctor w-rw-rw-
Jun 24, 2008

Thermopyle posted:

I dunno, if the volume of posts about null is anything to go by, null is the most serious problem since...Y2K!

I know you snark, but Y2K was legitimately a huge problem.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Doctor w-rw-rw- posted:

I know you snark, but Y2K was legitimately a huge problem.

Well, whatever.

Dessert Rose
May 17, 2004

awoken in control of a lucid deep dream...
It's a pretty good comparison, because programmers expend tons of effort to ensure that the enormous mistake from the past doesn't actually cause that much damage.

sarehu
Apr 20, 2007

(call/cc call/cc)

Volte posted:

What happens when the libraries you call don't pretend that

The answer is, unsurprisingly, you have to read libraries' API documentation.

mobby_6kl
Aug 9, 2009

by Fluffdaddy

Doctor w-rw-rw- posted:

I know you snark, but Y2K was legitimately a huge problem.

Yeah and all the tigers would've been a huge problem too if it weren't for my rock!

raminasi
Jan 25, 2005

a last drink with no ice
"This so-called 'problem' isn't a problem because you can just bolt your own conceptual constraints on top of the language and rely, never making any mistakes, on the comprehensive, accurate documentation for any libraries you use."

Soricidus
Oct 21, 2010
freedom-hating statist shill

sarehu posted:

The answer is, unsurprisingly, you have to read libraries' API documentation.

Now one of the libraries used by one of the libraries used by one of the libraries you use has changed in such a way that a method that used never to return null can now return null. One of the intermediate libraries does not share your passion for being incredibly careful and never making a single mistake. By some miracle all the library tests still pass (the miracle is that the library has tests at all), so nobody notices that the documentation of the library you are actually relying on is now incorrect. But now your code is getting unexpected NPEs.

This situation is literally impossible in a language where nullability is explicit, with basically no discernible downside except for occasionally maybe having to let your IDE type a few more characters for you.

No Safe Word
Feb 26, 2005

http://www.diogonunes.com/blog/custom-build-configurations-visualstudio/

How not to use build configurations with Visual Studio :doh:

I mean, yeah that's how you set them up. But it's not what they're for.

code:
#if   RELEASE_CLIENT_ABC
    bool _isDebug = false;
    Organization _currentOrg = new ClientABC();
#elif RELEASE_CLIENT_XYZ
    bool _isDebug = false;
    Organization _currentOrg = new ClientXYZ();
#elif RELEASE
    bool _isDebug = false;
    Organization _currentOrg = new DevTest();
#else
    bool _isDebug = true;
    Organization _currentOrg = new DevTest();
#endif
:sigh:

Space Kablooey
May 6, 2009


No Safe Word posted:

http://www.diogonunes.com/blog/custom-build-configurations-visualstudio/

How not to use build configurations with Visual Studio :doh:

I mean, yeah that's how you set them up. But it's not what they're for.

code:
#if   RELEASE_CLIENT_ABC
    bool _isDebug = false;
    Organization _currentOrg = new ClientABC();
#elif RELEASE_CLIENT_XYZ
    bool _isDebug = false;
    Organization _currentOrg = new ClientXYZ();
#elif RELEASE
    bool _isDebug = false;
    Organization _currentOrg = new DevTest();
#else
    bool _isDebug = true;
    Organization _currentOrg = new DevTest();
#endif
:sigh:

I did this once to change the constructor of a class. Not only the meat of it, but depending on the setting it also changed what arguments it took. :haw:

Adbot
ADBOT LOVES YOU

Knyteguy
Jul 6, 2005

YES to love
NO to shirts


Toilet Rascal

No Safe Word posted:

http://www.diogonunes.com/blog/custom-build-configurations-visualstudio/

How not to use build configurations with Visual Studio :doh:

I mean, yeah that's how you set them up. But it's not what they're for.

code:
#if   RELEASE_CLIENT_ABC
    bool _isDebug = false;
    Organization _currentOrg = new ClientABC();
#elif RELEASE_CLIENT_XYZ
    bool _isDebug = false;
    Organization _currentOrg = new ClientXYZ();
#elif RELEASE
    bool _isDebug = false;
    Organization _currentOrg = new DevTest();
#else
    bool _isDebug = true;
    Organization _currentOrg = new DevTest();
#endif
:sigh:

What a strange way to approach that particular problem. I mean I guess it's a little more automated... but huh. I wouldn't even think of that.

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