Coding Confession: how not to use LINQ



  • @boomzilla said:

    One of the things the compiler "wants"1 to do is to optimize the code given as input to make it run efficiently.

    Does it like flying kites and long walks on the beach? Can you hook me up with this compiler?



  • @blakeyrat said:

    You have to tell me what the compiler's like first.

    Wait, I know this one: More pedantic than anyone here!


  • ♿ (Parody)

    @blakeyrat said:

    Can you hook me up with this compiler?

    You aren't compatible. It's GPL3.



  • @boomzilla said:

    You aren't compatible. It's GPL3.

    That BITCH!


    This goes back to the thing when people were trying to explain the term "inversion of control". What's with developers who anthropomorphize this inanimate stuff and give it like the desire to control things, or say you need to see from its point-of-view or whatever? That's weird as shit.

    But weirder than that, they actually THEN SPREAD THE TERM AROUND assuming that everybody else does the same weird-ass anthropomorphizing as they do, as if that's normal and not straightjacket-bonkers.


  • ♿ (Parody)

    @blakeyrat said:

    That's weird as shit.

    It's a people thing. You wouldn't understand.



  • @blakeyrat said:

    This goes back to the thing when people were trying to explain the term "inversion of control"

    I assume they said things other than 'only give things what they require to operate', but whatever those things were, they were wrong.


  • BINNED

    @TwelveBaud said:

    Second, if a function has no side effects, you can replace it with its return value. You can do this at compile time (couple of the O flags do this) or at run time ("memoization", a lookaside cache of return values).

    I get this. I also get what @boomzilla is saying. My problem with this that the whole concept of what's called a "side effect" in this context.

    Maybe I have to be a mathematician then. To stupid old me side effect is a non-intended thing. You know, like when painkillers screw with your digestion. Or the printf formatting my hard drive example. As @blakeyrat said, it requires either a new word or a descriptive term.

    "External influence" sounds better to me. Probably not perfect either, but it gets the point across - it's outside of your control, but you can prepare for it. And you can intend for your program to deal with it. When I use printf that's my influence on the OS. When I get a keyboard interrupt it's the other way around. But in neither case would I call it a "side effect".


  • FoxDev

    @Onyx said:

    Maybe I have to be a mathematician then. To stupid old me side effect is a non-intended thing.

    I think of a side-effect in the same way that others have described it; an effect on something outside the function scope. But then I divide that into intended (printf() writing to the terminal) and unintended (printf() killing a badger). The intended ones are OK, the unintended ones less so ;)


  • ♿ (Parody)

    @Onyx said:

    Maybe I have to be a mathematician then.

    Maybe. At least, use precise terminology in specific contexts. It can be confusing when you're not familiar with the context to begin with. Of course, that's before the ESL issue. I can't imagine having to jump through that extra hoop. I'd probably sound like @blakeyrat.

    @Onyx said:

    But in neither case would I call it a "side effect".

    I dunno...it seems obvious and natural to me. 😄



  • @RaceProUK said:

    The intended ones are OK, the unintended ones less so

    If it's intended it's just an effect.


  • BINNED

    @boomzilla said:

    Of course, that's before the ESL issue.

    Might be. See, I know what "side effect" means. Now, even I can pretty much "think in English" (insert Firefox reference here), I know there is actual translation going on in my brain, somewhere. The word it gets translated to (nuspojava) is a word that I only ever heard in a context of "whoops, this shit is not what we wanted to do, but now we have to deal with it".


  • ♿ (Parody)

    @blakeyrat said:

    If it's intended it's just an effect.

    The effect has already been defined as the return value. That's what the function does, remember, on the level at which the compiler is working. Those other things are secondary, or side effects.

    You may intend them, but you may not use the wrong words here and not be corrected.



  • @boomzilla said:

    The effect has already been defined as the return value.

    A function can have multiple effects.

    @boomzilla said:

    That's what the function does, remember, on the level at which the compiler is working.

    I don't care about the level at which the compiler is working. Who does? If I wanted to think about that shit, I'd write assembly.

    @boomzilla said:

    Those other things are secondary, or side effects.

    If the term were "secondary effect" it would be 100,000 times better.


  • ♿ (Parody)

    @Onyx said:

    The word it gets translated to (nuspojava) is a word that I only ever heard in a context of "whoops, this shit is not what we wanted to do, but now we have to deal with it".

    Yeah, that's not quite the connotation here, but not totally far off, either. We are talking about a formal system here, i.e., math, and it's easy to let concepts leak into your thinking.


  • ♿ (Parody)

    @blakeyrat said:

    I don't care about the level at which the compiler is working.

    So stop talking about it already.



  • So in the end, the whole functional thing is trying to turn me into a compiler? As in, I have to make it's job easier?

    No, very much the opposite. But it does have trade-offs compared to a pure imperative language.

    I'm trying to understand the appeal of it here. I see some valuable ideas in the paradigm, but the whole "purity" thing rubs me the wrong way. It seems to be designed so I have to do more work for the benefit of the ideal, and the only reason is actually the ideal, not any actual benefits.

    This is because you don't know how you would actually write "functions with side-effects". That's what monads are for. A strongly typed language keeps the so-called "monadic expressions" conceptually distinct from the "functions", which are pure in the sense you've been discussing.

    (And in this case, it's the imperative programmers who introduced the usage in analogy to mathematical functions and are misusing the term. Functions always were side-effect free. What you guys are calling functions used to be called procedures)

    A monad is a strongly typed imperative minilanguage that attaches a "context" to a computation. So, for example, we can have the State monad, which is defined something like:

    data State s a = State s a
    

    so that s is the state you want the monad to pass around. The state monad type class defines getters and setters, so you can query the state and return a value based on it or modify it. In other words, State s attaches the context s to the return value a. In this way, you can keep your side-effect-ful code apart from the "pure" code. And you can write things like:

    tick :: State Int ()
    tick = do
      num <- get
      put $ num + 1
    

    Notice that the thing you're putting is purely pure. It is a noun, while put is a verb. Put very, very simply, the distinction between functional or not is whether nouns are first class, and the distinction between pure and impure is whether nouns can have effects.

    Monads are actually pure, too, but they do capture what is meant by side-effects. The IO monad is the only exception, because the runtime has to hook into the system to do IO.


  • Discourse touched me in a no-no place

    @boomzilla said:

    So stop talking about it already.

    You know that won't happen until you prove him wrong, or else someone mentions badges.


  • FoxDev

    @blakeyrat said:

    If the term were "secondary effect" it would be 100,000 times better.

    That's… not a bad idea actually; I'd go with that


  • ♿ (Parody)

    @FrostCat said:

    You know that won't happen until he realizes that you proved him wrong...

    Yes, I know.


  • BINNED

    I'm actually trying to remember a term I heard in a maths class that would relate, just to see what it would translate to (or figure out I've been talking out of my ass the whole time), but I can't think of anything ATM 😒



  • I'm a programmer, I don't know shit about math.


  • ♿ (Parody)

    @blakeyrat said:

    I don't know shit

    QFT

    @blakeyrat said:

    math

    When you program a computer, you do a lot of stuff that's really math, which isn't really about numbers and arithmetic. You often don't know the formal names (I'm not academically trained in CS, so my vocabulary is lacking, too) but you do a lot of abstract reasoning that it really applied math. I've argued with other pendants around here about this, but they're wrong.



  • I had to take a class called "Discrete Mathematics" which was basically an in-depth study of logic and Boolean logic.



  • @boomzilla said:

    When you program a computer, you do a lot of stuff that's really math, which isn't really about numbers and arithmetic.

    I do lots of logic, and with LINQ and SQL some set stuff. But nothing involving math.

    @boomzilla said:

    You often don't know the formal names (I'm not academically trained in CS, so my vocabulary is lacking, too) but you do a lot of abstract reasoning that it really applied math.

    I don't know the formal names of shit. I think that's why I'm such an awesome highly-valued programmer.

    @boomzilla said:

    I've argued with other pendants around here about this, but they're wrong.

    Everybody here is wrong all the time.


  • ♿ (Parody)

    @blakeyrat said:

    SQL some set stuff

    @blakeyrat said:

    But nothing involving math.

    You're contradicting yourself again.

    @blakeyrat said:

    Everybody here is wrong all the time.

    Oh. Right. Carry on then.


  • BINNED

    @Captain said:

    Notice that the thing you're putting is purely pure. It is a noun, while put is a verb. Put very, very simply, the distinction between functional or not is whether nouns are first class, and the distinction between pure and impure is whether nouns can have effects.

    Ok, I have no mathematical background (apart from requisite classes) and have to deal with ESL thing here, and this is just making my head spin.

    Now, for us unwashed in the terms, I'm trying to translate this, correct me where I'm wrong:

    Verb does things. It's a function, procedure, method, whatever you want to call it.
    Noun is... a value? So a variable? How do you make it impure then? Are you saying it's impure if the variable contains an object where the getter does stuff other than returning a value? Or if it even has any methods? If all I use are primitives, does that mean it's pure (that expression, at least)?

    I am confuse.


  • FoxDev

    In terms of functions, pure means no side-effects ;)



  • Let's stick to calling them procedures (at least in this discussion) so we don't get mixed up. So a 'verb' is a procedure. It does things, in the sense that it causes changes. You got that right.

    A noun is a value. It doesn't do things -- it just exists, and verbs do things to them (or with them). But, the probably tricky thing is that functions are values too. So you can have a function

    add :: Int -> Int -> Int
    add x y = x + y
    

    Now, you can say that add adds things together. I understand the temptation to call this a verb. (And, in an important sense, it is, since it belongs to the reader monad). What I'm saying, though, is that add is a noun in its own right. This is somewhat tangential to my point about nouns and verbs, purity and impurity.

    In Haskell, you could make a value impure by using the unsafePerformIO function, which would look something like:

    unsafeRandomInt :: Int
    unsafeRandomInt = unsafePerformIO $ getRandomInt
    

    Now, getRandomInt would have a type IO Int, so unsafePerformIO rips the random number out of its IO context, in a way that could be unsafe, since there is nothing stopping getRandomInt from performing an effect other than reading the number. Nobody like unsafePerformIO, and using it is a red flag. But it's a useful tool sometimes, too. You just have to know when it is safe.

    The distinction is easier to think about if you consider the architecture of a Haskell program. Each program has a main procedure, defined like:

    main :: IO ()
    main = do
      stuff
    

    It drives the computation. It does stuff. It calls functions and does things to nouns.

    If you did:

    main :: IO ()
        unsafeRandomInt
    

    it would be a type error, because the compiler expects a verb, not a noun.


  • FoxDev

    …and this is why I don't do pure functional programming 😆


  • BINNED

    @RaceProUK said:

    …and this is why I don't do pure functional programming 😆

    Concur. add is a noun? So... it "just exists". Ok. Aaand... since I don't know the syntax I'm guessing that add x y = x + y means "given x and y, return x + y". But... that's doing stuff! It's adding! Work has been done!

    I'm either stupid or the terminology is getting to me. In any case, I'll stick to my impure ways. This is not my cup of tea, I think.


  • FoxDev

    Pure functional programming is a very maths-heavy style; it's not for everyone. Thankfully, the functional influence on more mainstream programming styles doesn't require such a deep understanding ;)


  • ♿ (Parody)

    @Onyx said:

    I'm either stupid or the terminology is getting to me. In any case, I'll stick to my impure ways. This is not my cup of tea, I think.

    Here's a rule of thumb. If you call a function, the more you need to worry about various things happening (state changes, I/O), the less pure it is. So multiple things are happening (potentially) which is more complicated than just one thing happening that doesn't change anything anywhere. No action at a distance.

    You probably don't need to worry about it. But if you bring up stuff like that around here, you'll get an earful.


  • BINNED

    @boomzilla said:

    You probably don't need to worry about it.

    Well, you do, up to a point, but for different reasons: maintainability for one.

    I have a huge monstrosity in one of my services that really needs to get refactored completely due to this. It has a huge if-else statement in it and it really depends on too many things and does too many things too. If you want impure, boy do I have an example of that.

    It's just that we all draw the line on that in different places. From a pragmatic standpoint, I say the UNIX-style philosophy is damned close to getting it right - one program (procedure / function / method / class) does one thing and it does it well. Execution not so much at times, but I think it's a decent enough goal to shoot for.


  • Discourse touched me in a no-no place

    @Onyx said:

    From a pragmatic standpoint, I say the UNIX-style philosophy is damned close to getting it right - one program (procedure / function / method / class) does one thing and it does it well.

    A lot of those utilities (e.g., head, tail, cut) would be candidates for being regarded like pure functions. They do one thing, and just that thing; they don't write out to other files or otherwise mess around with the system. You feed them some input, you get some output. It's nice and simple to work with, and you can compose them to do really quite complicated stuff. Yes, the things in and out are a bit more complicated than the usual numbers that people use when doing their example functions :) but they're really just nice functions in a higher-level environment. (If you wanted to, you could save the output of the processing to a temp file and use that later instead; that would be just as good as rerunning the tool as long as the input is the same.)

    Compare and contrast with some random perl script. With that, just knowing it is a perl script doesn't tell you very much at all about what it does: it could be pretty much anything, including popping up a GUI, rebooting your database servers without warning, or starting WW3 for shits and giggles. (Actually, if it is Perl there's a real chance that it will do all of these things at once, and you'll never know — even if you read the code — until later whether you're to blame for the start of thermonuclear armageddon.) Perl's a tool that most certainly supports side-effects!

    Side effects make things harder to reason about. Much harder. OTOH, without any side effects then nothing of interest actually ever happens; they're often the whole damn point. (Or an implementation detail, which can happen if you've got a pure function which does impure things internally.)


  • ♿ (Parody)

    @dkf said:

    does impure things internally

    :giggity:



  • @RaceProUK said:

    …and this is why I don't do pure functional programming

    A simpler explanation:
    You have a class/object/thing called IO.
    IO can contain any value, however you can only read said value by passing a callback to an instance of IO.
    Specifically, Function<Value,ReturnValue> or Function<Value, IO<ReturnValue>>
    It's a tad more complicated, but that's the gist of it.
    An example in psuedo-C# of how it is generally used:

    class Program {
      static IO<void> Main() {
        IO<string> nameIO = IO.ReadLine();
        IO<void> saidIO = nameIO.WithValue(SayHello);
        return saidIO;
      }
      static IO<void> SayHello(string name) {
        return IO.Write("Hello " + name);
      }
    }
    

    In haskell, the language is structured in a way that you need to chain calls of IO together otherwise they will never be executed.
    I.E. the moment a method returns a type of IO<>, all methods which call it must also return a type of IO<>, otherwise the compiler will optimise it away as dead code.
    It's basically the GPL of object types.

    It's a dodgy hack to keep the 'purity' of functions by hiding the impure stuff behind compiler hacks. And if your Main() method does not return a type of IO<>, Your program will never output anything. Ever.
    Frankly, I'd rather System.out.println/Console.WriteLine any day of the week.



  • @Onyx said:

    It's just that we all draw the line on that in different places. From a pragmatic standpoint, I say the UNIX-style philosophy is damned close to getting it right

    Unless you're writing a GUI program, in which case it's horrible, tragically, utterly, wrong.


  • BINNED

    I mean that's a good guideline when writing functions / methods / procedures / verbs / dothingies or whatever the hip name is this week, not necessarily applications as a whole.

    I care more about the function making sense and doing only what it should than if doing IO is impure. If the function is meant to print stuff, it should print stuff. In my head it's not a "side effect", it's the desired effect.


  • BINNED

    @boomzilla said:

    > As in, I have to make it's job easier?

    I'm not a big functional programming guy (paging @Captain / @antiquarian / @tarunik ), but not having lots of side effects can make things easier for you.

    My experience coding in Haskell was that it is a bit more work up-front to satisfy the compiler, but once the code gets past the compiler it's more likely than not to just work without needing any debugging.



  • @Onyx said:

    Verb does things. It's a function, procedure, method, whatever you want to call it.Noun is... a value? So a variable? How do you make it impure then? Are you saying it's impure if the variable contains an object where the getter does stuff other than returning a value? Or if it even has any methods? If all I use are primitives, does that mean it's pure (that expression, at least)?

    Natural language analogy:

    In natural languages (English, for instance), there's a construct called a gerund, which allows you to use a verb in a context where a noun is expected. (English uses the -ing suffix on verbs to conjugate regular gerunds, perhaps you could share how Croatian does it?)

    Imperative-only computer languages (such as ALGOL descendants) lack this notion; slightly-more-modern languages such as C and Forth hack around this by providing a notion that can be used to express "address of function" (C function pointers, Forth execution tokens).

    Functional languages (or functionally-minded multi-paradigm languages, for that matter) extend this by making functions values in the language sense, and giving functions the ability to operate generically not only on values, but other functions as well. The English analogy is a verb whose object or subject is itself a gerund.

    "Pure" vs. "impure" is a different matter entirely -- in a "pure" functional language, the only thing your procedures give you back is a return value; "impure" code allows your procedures to go off and do other things (like printing to the screen or starting WWIII) as well.



  • @tarunik said:

    "Pure" vs. "impure" is a different matter entirely -- in a "pure" functional language, the only thing your procedures give you back is a return value; "impure" code allows your procedures to go off and do other things (like printing to the screen or starting WWIII) as well.

    I thought not returning something was what makes something a procedure, whereas returning something makes it a function? That's the way the terms have been defined to me, at least.



  • Not exactly the same kind of terminology. A functional language is based on lambda calculus and built on the idea that every function operates by taking some arguments, performing operations that do not change those arguments, and giving back one of more return values. Data is immutable, side effects are verboten, and they have these special cases (I think they're called monads?) that are used where side effects are necessary, like for actual output.

    At least that's as well as I've understood it so far. I've used languages with first-class functions but not pure functional languages, so I am basing my interpretation largely off of reading blogs.

    Edit P.S.: And then there's T-SQL, where functions have return values and (except in very screwy cases) cannot have side effects, while procedures can have side effects, and have very restricted return values but can give back information in output variables or result sets...



  • I'm just pendanting his use of 'procedure' as 'thing with a return value'



  • @Magus said:

    I thought not returning something was what makes something a procedure, whereas returning something makes it a function? That's the way the terms have been defined to me, at least.
    Different contexts have different definitions. Some languages make the distinction you say, but in the context of functional languages, the "functional" part of the name is meant to indicate that you're programming with things that are literally mathematical functions, which is just a mapping from an input to an output. You give it an input, and it will give you the corresponding output, and it will always give you the same output for the same input.

    (Actually, to complicate this further that's not even entirely true. There are two distinct uses of "functional language"; one of them is analogous to "pure functional language", and that's what I talk about above. A weaker definition (in practice) is a language it which functions are first-class objects, can be passed around, etc.)



  • Concur. add is a noun? So... it "just exists". Ok. Aaand... since I don't know the syntax I'm guessing that add x y = x + y means "given x and y, return x + y". But... that's doing stuff! It's adding! Work has been done!

    What I mean by "it just exists" is something kind of "formal". When you write the mathematical symbols (5 + 3), you're not actually adding anything. You're just saying "This expression means "(5 + 3)". And when you say "5 + 3 = 8", you still haven't added anything. You've said that the expression "8" can always be substituted for 5 + 3.

    In the same way, the addition function can be thought of as a giant data structure "in the sky", consisting of triples (x,y,z) such that (x + y = z). And when we actually call add (in impure code), we're (conceptually) performing a query on the data structure we named add. We can pass this data structure around -- not in memory as a pointer or a copy, but in thought. As a concept, with a type.

    And if different data structures/concepts have the same type, we can use them in the same places. We'll perform different queries, but we can pass the queries around very naturally.

    Purity lets us do some reasoning. For example, since add is a pure function, we know that. add x y will always return x + y, with no side effects. We know it won't launchTheMissles, which we know has the type IO () anyway.

    We also know that add x y won't sometimes return x + y and sometimes return x + y + 1. Every time we call add 1 2, we will get 3. This is in general true for pure functions (a property called referential transparency).

    This is not true for commands/verbs, which depends on non-mathematical objects like the state of the world. For example, calling getRandomInt (which has type IO Int) will get us a random integer, but it won't be the same one every time (i.e., the IO context is not referentially transparent). The integer returned depends on the state of the random number generator, and not the inputs to the function.

    Purity enforces this property statically.



  • PEDANT alert.... There are NO pure functions, every function has a side effect.


  • BINNED

    Ah, but are there pure procedures? :trollface:


  • FoxDev

    @TheCPUWizard said:

    There are NO pure functions, every function has a side effect.

    Convoluted example, but:

    function add(a, b) {
        return a + b;
    }
    

    Looks pretty pure to me 😛


  • BINNED

    You touched the stack! BadImpure programmer!


    Filed under: SPANK


  • FoxDev

    @Onyx said:

    You touched the stack!

    :giggity:
    @Onyx said:
    SPANK

    …if I have to be… and so long as a certain fox does it…


Log in to reply