Coding: Fleeting Thoughts

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
Xeio
Friends, Faidites, Countrymen
Posts: 5100
Joined: Wed Jul 25, 2007 11:12 am UTC
Location: C:\Users\Xeio\
Contact:

Re: Coding: Fleeting Thoughts

Postby Xeio » Mon Jan 19, 2015 8:03 pm UTC

Sometimes it's easy to not notice how useful a convention is until someone goes and breaks that convention.

Like returning a null instead of an empty collection.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11109
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Mon Jan 19, 2015 8:08 pm UTC

The convention being to do that, or not to do that? I could see either option being horrible if you where used to the alternative.

I guess in heavy languages (where you can only return magic pointers), empty collections are expensive objects for something whose value is summed up by "nothing here".

Downside is that calling code cannot uniformly interact with it without always checking for null. But in languages where almost everything is nullable, you end up having to do that anyhow, no?

I miss value semantics when they aren't there.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6469
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Mon Jan 19, 2015 8:15 pm UTC

My experience with C# developers is that a lot of them hate nulls with a passion, and instead prefer to invent their own convention for something that means null but doesn't throw an exception if you forget to check it. So strings will be empty, and numbers will be zero or -1, and they don't have to deal with exceptions but instead the program just sometimes works incorrectly and you have a lot harder time figuring out where the problem is.
Summum ius, summa iniuria.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1443
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Mon Jan 19, 2015 8:36 pm UTC

My experience is that a lot less code fails when faced with empty containers the programmer wasn't expecting than when faced with nulls the programmer wasn't expecting.
But when the empty container code fails, the error may not be so obvious.
Image

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6469
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Mon Jan 19, 2015 8:44 pm UTC

Empty containers are usually less of a problem than setting ints to 0. Empty container (or strings) is actually descriptive of what it is.
Summum ius, summa iniuria.

User avatar
Xeio
Friends, Faidites, Countrymen
Posts: 5100
Joined: Wed Jul 25, 2007 11:12 am UTC
Location: C:\Users\Xeio\
Contact:

Re: Coding: Fleeting Thoughts

Postby Xeio » Mon Jan 19, 2015 9:31 pm UTC

Yakk wrote:The convention being to do that, or not to do that? I could see either option being horrible if you where used to the alternative.
.Net (or just C#?) convention is to never return null for collections or arrays. The exception may be error states, but you should most probably be throwing in those cases.

Strings are probably the "collection" where there isn't a solid convention, but the standard string.IsNullOrWhitespace method happens to handle both unless the null is significant.

Thesh wrote:My experience with C# developers is that a lot of them hate nulls with a passion, and instead prefer to invent their own convention for something that means null but doesn't throw an exception if you forget to check it. So strings will be empty, and numbers will be zero or -1, and they don't have to deal with exceptions but instead the program just sometimes works incorrectly and you have a lot harder time figuring out where the problem is.
I'm not sure why nullables seem so unpopular. I mean TryParse and similar work well, but int? as a return type could do the same job.

Nullables can make defaulting cleaner too, particularly with the null coalescing operator:

Code: Select all

int something = nullableInt.Parse("foo") ?? 5;

//vs

int something;
if(!int.TryParse("foo", out something)){
    something = 5;
}

User avatar
Yakk
Poster with most posts but no title.
Posts: 11109
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Mon Jan 19, 2015 9:42 pm UTC

With nullable types not being the default in C++, I have an `optional` which is a nullable value-semantics wrapper around anything.

The consumer knows that it is optional, and it could be "not there", so they **check** each time. The fact you have to * or -> makes it more memorable (as in C++, pointers are also nullable).

They can do a "if( maybe_set ) { }" to get a branch where the set is set, or even "if (auto elements = get_elements())", and avoid having to check it each time.

As a bonus, I never ever use flag values any more. An optional<int> says what it means far more clearly. And because I did an explicit type annotation that it is possibly empty, the user has documentation that they should check (unlike in C#, where you are forced to use nullable types, which means that even when you never pass a null you have to pass a nullable type, so consumers can be used to never getting nulls despite the type being nominally nullable).

I wonder why Java and C# went with "all objects must be pointers"? You can have value-semantic objects with smart pointers that self-null when the object goes out of scope in a managed language, and have them throw if used on an object that is gone.

This does create the category of "smart lifetime" objects and "automatic lifetime" objects. You could distinguish between these two categories of object, and even have the pointer-type to them be different -- strong pointers for "smart lifetime", weak pointers for either "smart lifetime" or "automatic lifetime" objects.

As a bonus, you'd get RAII.

Maybe there is some fundamental reason I'm missing? I guess the main thread disposing of an object as another thread tries to access it is a bit annoying?
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
cemper93
Posts: 209
Joined: Sun Feb 20, 2011 2:35 pm UTC
Location: `pwd`

Re: Coding: Fleeting Thoughts

Postby cemper93 » Mon Jan 19, 2015 10:11 pm UTC

The consumer knows that it is optional, and it could be "not there", so they **check** each time. The fact you have to * or -> makes it more memorable (as in C++, pointers are also nullable).

Kind of like Haskell does it with the Maybe type. A function that returns Maybe a can either return a value of data kind Just a or the value Nothing. If the call site of such a function is not itself in the Maybe monad, then the value of type a has to be extracted by hand -- usually by pattern matching -- before it can be used.

Code: Select all

halfOfInt :: Int -> Maybe Int
halfOfInt i
    |even i = Just (i `div` 2)
    |odd i = Nothing

otherFunction :: Int -> Stuff
otherFunction i =
    case (halfOfInt i) of
        Just j -> someStuff j
        Nothing -> otherStuff


EDIT: Obviously the Maybe type is mostly as a monad or functor, not because it forces value extraction. But still a good pattern, I think.
Last edited by cemper93 on Mon Jan 19, 2015 10:45 pm UTC, edited 1 time in total.

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6469
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Mon Jan 19, 2015 10:29 pm UTC

Xeio wrote:I'm not sure why nullables seem so unpopular. I mean TryParse and similar work well, but int? as a return type could do the same job.


Yeah, I'm primarily a database guy, and when I write C# I always use nullable types when working with the database, but other developers have complained and wanted me to return 0 or -1 whenever we had a numeric type, which I thought was insane (especially since sometimes those are meaningful values) and we got in huge arguments in the meeting rooms. They are nullable in the database for a reason: because there's not always a value.

Where I work now, there are no nullable types in the database at all, and we use 0, -1, 99999, and other absurd values to indicate invalid data, and it varies from column to column depending on which ones are considered valid all because the C# team lead doesn't like dealing with nulls.

Also, what is great fun is when we do calculations based on the date in SQL, and now have to check to make sure it is not our psuedo-null value, "1900-01-01"; we do more work dealing with the bad values then we save by checking if it's null because in most cases if the value is null, it makes sense for the calculation to just return null as well which happens without doing anything.

As for returning sets, I think empty tends to make more sense logically for most situations when there is nothing to return; I can't think of a case where returning null makes more sense.
Summum ius, summa iniuria.

Breakfast
Posts: 117
Joined: Tue Jun 16, 2009 7:34 pm UTC
Location: Coming to a table near you

Re: Coding: Fleeting Thoughts

Postby Breakfast » Tue Jan 20, 2015 12:57 pm UTC

Thesh wrote:
Xeio wrote:I'm not sure why nullables seem so unpopular. I mean TryParse and similar work well, but int? as a return type could do the same job.


Yeah, I'm primarily a database guy, and when I write C# I always use nullable types when working with the database, but other developers have complained and wanted me to return 0 or -1 whenever we had a numeric type, which I thought was insane (especially since sometimes those are meaningful values) and we got in huge arguments in the meeting rooms. They are nullable in the database for a reason: because there's not always a value.

You're right, this is insane. I've been developing with C# and SQL for quite a few years now and could not imagine how forcing nullable database types into non-nullable code types could be any kind of useful. That being said, C# does need a much better way of dealing with nullable types. What they did with the Nullable<T> generic was almost the Maybe monad. They just missed the mark and didn't give us a good Bind.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11109
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Tue Jan 20, 2015 2:40 pm UTC

Breakfast wrote:They just missed the mark and didn't give us a good Bind.

So, optional<T> in C++1z will be a Maybe (a nullable type).

What we need is a good Haskell Bind. We cannot, however, call it Bind, and >>= is a bad idea. We could use invoke. And curried functions are not idomatic in C++, so lets avoid that.

Instead, we want to take f( args..., optional<T>, more_args... )->X, when f takes (args..., T, more_args...), and return an optional<X> that exists iff the optional<T> exists. However, if f takes an optional<T> already at that location, we don't want to do this.

And in C++, you cannot determine the signature of a function without passing arguments. Barring language support, we need to check an exponential number of calls, and error out if the result is ambiguous.

invoke_result_t< F( args... ) > is easy to write.

Next, we'll want to take args..., extract all optional<T>s from it (lvalue or rvalue), and swap each subset with a T. This generates 2^n where n is the number of optional<T> different packs. Fortunately n is usually small.

Then check invoke_result_t< F(args...) > for each of these "substituted" signatures to see if the call matches, and under the obvious partial order pick the "best" match. Maybe also order by "number of optional<T>" to break ties, but I think not: better to error than surprise.

If the "best" match is anything but the original args..., the return value becomes optional<X> if it was not already optional (questionable choice, but I think wise: optional<optional<X>> is surprising). We then test each of the optional<T> -> T transforms, and if they all pass we invoke F on the result. If not, we return nullopt.

A way to do this explicitly, or assume that the underlying F should fail if any of the inputs fail even if it "thinks" it can eat an optional, might be useful. The notation gets messy if you want to do this partially.

Thoughts?
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
cemper93
Posts: 209
Joined: Sun Feb 20, 2011 2:35 pm UTC
Location: `pwd`

Re: Coding: Fleeting Thoughts

Postby cemper93 » Tue Jan 20, 2015 2:56 pm UTC

Well, outside of functional programming, bind isn't really useful in the first place. However, afaik (my C++ is no good) you could implement an in-place fmap in C++, which also gives you the advantages of the Maybe type, while staying in an imperative style.

EDIT:
However, if f takes an optional<T> already at that location, we don't want to do this.

I don't see why not. Maybe Maybe Int is totally a thing.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11109
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Tue Jan 20, 2015 3:04 pm UTC

Sure, but at that spot, we have a function with an overload (int, optional<double>)->bool.

We call it with (int, optional<double>). Even if the optional<double> is nullopt, we want to call the function with it, and return bool. The function knows how to consume that optional<double> in the 2nd argument spot, no point in wrapping it in a guard?
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
cemper93
Posts: 209
Joined: Sun Feb 20, 2011 2:35 pm UTC
Location: `pwd`

Re: Coding: Fleeting Thoughts

Postby cemper93 » Tue Jan 20, 2015 3:11 pm UTC

The function knows how to consume that optional<double> in the 2nd argument spot, no point in wrapping it in a guard?

But what if the value you're fed from the LHS of the bind operator is Just Nothing?

Breakfast
Posts: 117
Joined: Tue Jun 16, 2009 7:34 pm UTC
Location: Coming to a table near you

Re: Coding: Fleeting Thoughts

Postby Breakfast » Tue Jan 20, 2015 3:21 pm UTC

Yakk wrote:
Breakfast wrote:They just missed the mark and didn't give us a good Bind.

*stuff...*

If the "best" match is anything but the original args..., the return value becomes optional<X> if it was not already optional (questionable choice, but I think wise: optional<optional<X>> is surprising). We then test each of the optional<T> -> T transforms, and if they all pass we invoke F on the result. If not, we return nullopt.

Thoughts?

I'm not very well versed in C++ so I'll being deferring to your knowledge and expertise on most of that. As far as optional<optional<X>> goes, in all the literature and examples I've seen it could just be flattened to optional<X>. That outer wrapping isn't really serving much purpose.

In C# we've had the null-coalescing operator ?? for quite some time and we just recently got this thing: ?. (though I don't really care for that syntax). None of this really feels good to me though and I'd much prefer something like LINQ for Nullable<T>.

Code: Select all

int? x = null;
// Set y to the value of x if x is NOT null; otherwise,
// if x = null, set y to -1.
int y = x ?? -1;

// standard convention
int? value = GetValue();
if (value != null)
{
  // stuff..
}

// only calls Stuff() if value is not null
value?.Stuff()

User avatar
cemper93
Posts: 209
Joined: Sun Feb 20, 2011 2:35 pm UTC
Location: `pwd`

Re: Coding: Fleeting Thoughts

Postby cemper93 » Tue Jan 20, 2015 3:37 pm UTC

I'd consider an implementation that always performs the monadic join implicitly incorrect. For example:

Code: Select all

import Control.Monad
import Data.List

data Person = Person {uid :: Int, name :: String, birthplace :: Maybe String}

doSomething :: [Person] -> Int -> Maybe (Maybe String)
doSomething l i =
    (find (\x -> i == uid x) l)
    >>= (\person ->
        return $ case (birthplace person) of
            Nothing -> Nothing
            Just x -> Just x)

giveBirthplaceOrError :: Maybe (Maybe String) -> String
giveBirthplaceOrError a =
    case a of
        Nothing -> "no such person"
        Just b -> case b of
            Nothing -> "no birthplace for this person"
            Just c -> c

main :: IO ()
main = do
    let people = [Person 0 "John" (Just "New York"), Person 2 "Alice" Nothing]
    forM_ [0..2] (\i ->
        putStrLn $ giveBirthplaceOrError $ doSomething people i)


EDIT: Eh, actually not such a great example, since in this case it probably actually wouldn't matter. But you get the idea.
EDIT2: Changed to example where it does matter.

Nyktos
Posts: 138
Joined: Mon Mar 02, 2009 4:02 pm UTC

Re: Coding: Fleeting Thoughts

Postby Nyktos » Wed Jan 21, 2015 2:13 am UTC

Breakfast wrote:I'm not very well versed in C++ so I'll being deferring to your knowledge and expertise on most of that. As far as optional<optional<X>> goes, in all the literature and examples I've seen it could just be flattened to optional<X>. That outer wrapping isn't really serving much purpose.
In Rust, iterators return Option<T> from their next() method, returning None to indicate that there are no items left. An Iterator<Option<T>> returning Some(None) is quite different (and such a thing could certainly come up when iterating over, say, a list of accumulated results from some function that returns Option<T>)

User avatar
Yakk
Poster with most posts but no title.
Posts: 11109
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Wed Jan 21, 2015 4:45 am UTC

Sure, the only option being optional collapsing would be impolite. But an easy option being optional collapsing, even the easier option, is worthwhile.

In a sense, if you phrase the question "what is the birthdate of bob", the answer "I don't have a birthdate for bob" is a valid answer if either we have an entry for bob but it has no birthdate, or if we don't have an entry for bob. Being able to distinguish between those two cases is also useful, but the question "do we have an entry for bob" might be one we want to ask separately from the birthdate question.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

Breakfast
Posts: 117
Joined: Tue Jun 16, 2009 7:34 pm UTC
Location: Coming to a table near you

Re: Coding: Fleeting Thoughts

Postby Breakfast » Wed Jan 21, 2015 12:51 pm UTC

Nyktos wrote:
Breakfast wrote:I'm not very well versed in C++ so I'll being deferring to your knowledge and expertise on most of that. As far as optional<optional<X>> goes, in all the literature and examples I've seen it could just be flattened to optional<X>. That outer wrapping isn't really serving much purpose.
In Rust, iterators return Option<T> from their next() method, returning None to indicate that there are no items left. An Iterator<Option<T>> returning Some(None) is quite different (and such a thing could certainly come up when iterating over, say, a list of accumulated results from some function that returns Option<T>)

Yakk wrote:Sure, the only option being optional collapsing would be impolite. But an easy option being optional collapsing, even the easier option, is worthwhile.

In a sense, if you phrase the question "what is the birthdate of bob", the answer "I don't have a birthdate for bob" is a valid answer if either we have an entry for bob but it has no birthdate, or if we don't have an entry for bob. Being able to distinguish between those two cases is also useful, but the question "do we have an entry for bob" might be one we want to ask separately from the birthdate question.


It seems pretty obvious when it gets pointed out. My inexperience with monadic concepts is showing as I was only thinking of the Just<Just<x>> and the None<None> cases. Thanks goes to the both of you; I've learned something already today.

User avatar
Diadem
Posts: 5654
Joined: Wed Jun 11, 2008 11:03 am UTC
Location: The Netherlands

Re: Coding: Fleeting Thoughts

Postby Diadem » Wed Jan 21, 2015 2:37 pm UTC

A couple of colleague's of mine are following a C++ course. It's an introductory course, aimed at people with programming experience, but not c++ experience.

The topics covered are all language syntax. The first chapter is differences between C and C++, then the rest of the material explains classes, inheritance, overloading, templates, the standard library, etc. It seems to cover most of the language, but only the syntax. There's not good coding practices for C++. Nothing about RAII, nothing about the rule of three, nothing about avoiding raw pointers or arrays.

This struck me as a very poor way to set up a C++ course, even a beginner's course. It seems much better to begin with proper techniques and the overall C++ philosophy. Others disagreed. Sure it's a 4 day beginner course, and if you focus on those subjects than you might not b e able to cover the entire C++ syntax. But I'd say a beginner is better of knowing about RAII but not templates, than the other way around. The counter argument is that you won't be able to read real C++ programs if you don't know all the syntax, which I admit is a downside. But on the other hand learning syntax is generally quite easy once you start working with a language.

I was wondering about the opinions here.
It's one of those irregular verbs, isn't it? I have an independent mind, you are an eccentric, he is round the twist
- Bernard Woolley in Yes, Prime Minister

User avatar
Yakk
Poster with most posts but no title.
Posts: 11109
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Wed Jan 21, 2015 2:53 pm UTC

No, you aren't going to cover most of C++ syntax in 4 days. Where would you fit the bearded noop?

<:]{%>

More seriously, SFINAE, when you need to typename or template, template template parameters, type deduction, perfect forwarding, forwarding references (aka universal references), l-r-x-p-value rules, elision rules, 2-phase lookup in templates, ADL/koenig lookup, reference lifetime extension, uniform initialization, initializer lists, happens-before and happens-after (sequencing), the C++ memory model, overloading vs overriding functions, partial and full template class specializations, full template function specialization vs overriding, plain old data and descendent concepts, strict aliasing, undefined integer overflow and other insanity, nullptr, value decay vs std::decay, volatile vs mutable vs const, return type deduction, ...

I think none of the above covers "best practices", but just topics required to understand what a given C++ program would do. Trying to teach someone to understand "every C++ program" (ie, what it does, and why it does it), even barring obfuscated ones, is not a 4 day course.

I'd be very tempted to split the course into two. "Reading C++ programs" and "Writing C++ programs" portions. Both are required, and being comprehensive at either isn't going to happen.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Diadem
Posts: 5654
Joined: Wed Jun 11, 2008 11:03 am UTC
Location: The Netherlands

Re: Coding: Fleeting Thoughts

Postby Diadem » Wed Jan 21, 2015 3:29 pm UTC

Yeah perhaps I should have said "seems to cover most of the language basics". You are right that none of those typics are covered, and probably shouldn't be covered in a beginner's course.

But the basic question I was wondering about is: Should a beginner's course on C++ mostly focus on language syntax, or mostly focus on 'best practices'?
It's one of those irregular verbs, isn't it? I have an independent mind, you are an eccentric, he is round the twist
- Bernard Woolley in Yes, Prime Minister

User avatar
phlip
Restorer of Worlds
Posts: 7565
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Thu Jan 22, 2015 12:02 am UTC

Well... if you know the syntax, but you don't know the best practices, you're going to be a bad C++ programmer, but who could potentially get better with practise and further study. If you know the best practices but not the syntax, you're just straight-up not going to be a programmer.

If you wanted to build a house, would you rather have a hammer but not really know the best way to use it, or be the world's foremost expert on hammer technique but not actually own a hammer?

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

User avatar
cemper93
Posts: 209
Joined: Sun Feb 20, 2011 2:35 pm UTC
Location: `pwd`

Re: Coding: Fleeting Thoughts

Postby cemper93 » Thu Jan 22, 2015 4:28 pm UTC

I guess what matters is who the course's audience is. If it's targeted at novice programmers, you're going to have to cover a lot more syntax and the semantics of simple built-in language constructs like conditionals, loops et cetera than when it's targeted at programmers that are already proficient in other languages, in which case you can get away with showing a simple "hey, this is how all those things you already know look in C++" slide and then moving on to the things that are more specific to the language or low-level programming (RAII, destructors, pointers and smart pointers, templates, etc).

User avatar
Xenomortis
Not actually a special flower.
Posts: 1443
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Thu Jan 29, 2015 2:28 pm UTC

Big abstract class with a method (fully implemented, but not final) that needs a unit test, and an empty constructor.
The method provides some information about the state of the class.

Do I put in a lot of effort to mock this class to get it to behave enough like a concrete class so I can test this method, or I do just add the tests to the concrete classes that inherit the abstract class (that have long, complicated constructors, that do most of what I'd end up mocking)?

And since the method isn't final (virtual), I feel the derived classes should probably be testing this themselves anyway.
Image

User avatar
raudorn
Posts: 370
Joined: Mon Jun 13, 2011 11:59 am UTC

Re: Coding: Fleeting Thoughts

Postby raudorn » Thu Jan 29, 2015 9:08 pm UTC

Today at work I got smacked across the face (metaphorically) so hard by our shitty codebase, that I'll be seeing stars until next monday. I won't go into detail just how shitty we're talking here (we'd still be here till next monday), but let me give you an example to scare you (the shock should last to next monday).

Code: Select all

// Assume $title has a value like "Foo_Bar_01" or "Foo 2 bar_04"
preg_match_all('/([a-zA-Z0-9_ ])+_(([0-9]{4}-[0-9]{2}-[0-9]{2})+?_.+ || ([0-9])+)/', $title, $matches);
if (isset($matches[0][0]) {
    $title = trim(str_replace('_', ' ', $matches[0][0]));
}


When I looked at this snippet first I was trying to figure out how it worked. The author apparantely wanted to extract everything before the last part, which could either be a datestring or just some numbers. And it worked,. But it shouldn't, the pattern is just not valid regex syntax. I thought that maybe it was some special magic, but I just could not find out how it worked nor could I find any reference to the use of double pipes in pattern matching. Then I finally understood how it worked: It doesn't.

What actually happens is, that preg_match_all tries to compile the pattern, but fails at the part with the double pipes. At that point it doesn't stop or anything, it throws the bad part out and continues with the pattern looking like this:

Code: Select all

preg_match_all('/([a-zA-Z0-9_ ])+_/', $title, $matches);

Now this almost matches what we actually want, for example the "Foo_Bar_" part of "Foo_Bar_01". The author then replaces the underscores by spaces (also replacing the first underscore, but that was a problem for another rant), trims the last space away and end up with the string he wanted, because preg_match_all puts the string that matches the whole pattern in $matches[0][0]. The grouping with paranthesis is a red herring for this "solution".

That was the part where I threw my hands up in disgust and loudly proclaimed my opinion of the author1, for the amusement of my coworkers (who are by now used to the madness of the mess we call software).

1 Look, I understand that the author probably did not do this intentionally. Most likely he was under pressure and went ahead as soon as he got something that worked. I would have done the same, in all likelyhood. It's still terrible.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: Coding: Fleeting Thoughts

Postby EvanED » Thu Jan 29, 2015 10:16 pm UTC

raudorn wrote:What actually happens is, that preg_match_all tries to compile the pattern, but fails at the part with the double pipes. At that point it doesn't stop or anything, it throws the bad part out and continues...
In my opinion, this is The Real WTF™ in your story.

Then again, I'm assuming that code is PHP so that is probably completely unsurprising.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1443
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Thu Jan 29, 2015 10:19 pm UTC

EvanED wrote:Then again, I'm assuming that code is PHP so that is probably completely unsurprising.

That was my first thought.
Image

User avatar
chridd
Has a vermicelli title
Posts: 836
Joined: Tue Aug 19, 2008 10:07 am UTC
Location: ...Earth, I guess?
Contact:

Re: Coding: Fleeting Thoughts

Postby chridd » Thu Jan 29, 2015 10:19 pm UTC

raudorn wrote:

Code: Select all

preg_match_all('/([a-zA-Z0-9_ ])+_(([0-9]{4}-[0-9]{2}-[0-9]{2})+?_.+ || ([0-9])+)/', $title, $matches);
[...]But it shouldn't, the pattern is just not valid regex syntax.[...]What actually happens is, that preg_match_all tries to compile the pattern, but fails at the part with the double pipes. At that point it doesn't stop or anything, it throws the bad part out and continues with the pattern looking like this:
Actually, I believe that second part is valid (but probably not what was intended), and means to match one of:
  • that long expression matching dates (which, if there are more than one, have nothing separating them...), followed by a space, or
  • an empty string (since that's what's between the first and second bar), or
  • a space, followed by any number of digits
~ chri d. d. /tʃɹɪ.di.di/ (Phonotactics, schmphonotactics) · she(?)(?(?)(?))(?(?(?))(?))(?) · Forum game scores
mittfh wrote:I wish this post was very quotable...
chridd (on Discord) wrote:
Dummy wrote:Sorry You're Gay Dads
SYG'D
marionic (on Discord) wrote:sleep in grave

User avatar
raudorn
Posts: 370
Joined: Mon Jun 13, 2011 11:59 am UTC

Re: Coding: Fleeting Thoughts

Postby raudorn » Fri Jan 30, 2015 11:56 am UTC

chridd wrote:Actually, I believe that second part is valid (but probably not what was intended), and means to match one of:
  • that long expression matching dates (which, if there are more than one, have nothing separating them...), followed by a space, or
  • an empty string (since that's what's between the first and second bar), or
  • a space, followed by any number of digits


I think you're right. It is valid syntax, just completely not what was intended. It also happens to be indistinguishable from the 'ignore errors' case I first hypothesised. Oh well, this makes this whole mess one epsilon less terrible.

schapel
Posts: 244
Joined: Fri Jun 13, 2014 1:33 am UTC

Re: Coding: Fleeting Thoughts

Postby schapel » Sat Jan 31, 2015 6:30 pm UTC

This week at work, I realized that when I added scrollbars to our Linux applications that the custom colors on the UI elements in that scrolled window would disappear. This was mystifying to me for hours until I finally found these resource rules for the applications:

Code: Select all

APPNAME*ScrolledWindow*Foreground: white
APPNAME*ScrolledWindow*Background: blue

These rules say that anything inside any scrolled window in any application should appear white on blue. So of course whenever I put anything inside a scrolled window all the custom colors for the UI elements disappear!

What makes this so notable is that my co-workers have been working around this issue for years by adding all sorts of complicated rules for every UI element inside any scrolled area in every application. I suppose it's easier to just make it work and move on rather than get to the root of the problem. But the time spent doing that over and over again sure will add up in the long run...

I fixed the issue once and for all by changing those two lines:

Code: Select all

APPNAME*ScrolledWindow.Foreground: white
APPNAME*ScrolledWindow.Background: blue
APPNAME*ScrolledWindow.XmText.Foreground: white
APPNAME*ScrolledWindow.XmText.Background: blue

These rules apply only to the scrolled window itself and a text UI element directly inside a scrolled window, which was what was originally intended.

User avatar
Sizik
Posts: 1237
Joined: Wed Aug 27, 2008 3:48 am UTC

Re: Coding: Fleeting Thoughts

Postby Sizik » Wed Feb 04, 2015 8:15 pm UTC

I kind of want to make a C (or C++) compiler that wipes your hard drive upon encountering undefined behavior.
gmalivuk wrote:
King Author wrote:If space (rather, distance) is an illusion, it'd be possible for one meta-me to experience both body's sensory inputs.
Yes. And if wishes were horses, wishing wells would fill up very quickly with drowned horses.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11109
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Wed Feb 04, 2015 8:27 pm UTC

... unless you pass the --lack_conviction flag
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1443
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Wed Feb 04, 2015 9:22 pm UTC

That made me laugh more than I think it should have done.
Image

User avatar
Dason
Posts: 1311
Joined: Wed Dec 02, 2009 7:06 am UTC
Location: ~/

Re: Coding: Fleeting Thoughts

Postby Dason » Thu Feb 05, 2015 3:39 am UTC

Not exactly the same but that reminds me of: https://github.com/munificent/vigil
double epsilon = -.0000001;

User avatar
phlip
Restorer of Worlds
Posts: 7565
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Thu Feb 05, 2015 4:28 am UTC

There was a website I came across many many years ago, that I've never been able to find again (not entirely sure that it still exists) that served as the instruction manual for a fictional C compiler that wired all undefined behaviour to explosives of various descriptions... It included a "valued clients"-type list, complete with pictures of the craters or mushroom clouds that are all that are left of their offices after they tried to compile a program with a buffer overflow, or tried to include <conio.h> (which they explained was their proprietary header for controlling nuclear missile silos).

It was quite well-written, and I wish I could find it again, but I can't remember enough searchable details...

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

User avatar
Thesh
Made to Fuck Dinosaurs
Posts: 6469
Joined: Tue Jan 12, 2010 1:55 am UTC
Location: Colorado

Re: Coding: Fleeting Thoughts

Postby Thesh » Thu Feb 05, 2015 5:30 am UTC

Summum ius, summa iniuria.

User avatar
phlip
Restorer of Worlds
Posts: 7565
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Thu Feb 05, 2015 5:34 am UTC

Holy crap, that's the one! Thanks!

The site is a lot uglier than I remember, but then, that's websites from the 90s for you...

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

User avatar
Xeio
Friends, Faidites, Countrymen
Posts: 5100
Joined: Wed Jul 25, 2007 11:12 am UTC
Location: C:\Users\Xeio\
Contact:

Re: Coding: Fleeting Thoughts

Postby Xeio » Fri Feb 06, 2015 8:31 pm UTC

and has been chosen as the deadlock victim
This error amuses me.

Blood for the deadlock gods!

User avatar
You, sir, name?
Posts: 6983
Joined: Sun Apr 22, 2007 10:07 am UTC
Location: Chako Paul City
Contact:

Re: Coding: Fleeting Thoughts

Postby You, sir, name? » Sat Feb 07, 2015 11:20 am UTC

Sizik wrote:I kind of want to make a C (or C++) compiler that wipes your hard drive upon encountering undefined behavior.


I think Valve may be way ahead of you on that one ;-)
I edit my posts a lot and sometimes the words wrong order words appear in sentences get messed up.


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 6 guests