Procedural, Object Oriented and Functional Programming Explained | Coding Concepts

Поділитися
Вставка
  • Опубліковано 21 лис 2024

КОМЕНТАРІ • 31

  • @madlep
    @madlep 3 місяці тому +6

    10:28 It’s not so much that functional “gets a bit weird”, it’s more that this code doesn’t really make use of the language tools available. You almost never want to manually manage recursion when you’re iterating over a collection when you’re doing FP, and instead would want to use higher order `map` / `reduce` etc functions provided by the language or a library. I’m not an expert on C#, but from what I understand `Select()` and `Aggregate()` function call would do the trick here.

  • @fungibungi5568
    @fungibungi5568 3 місяці тому +3

    clear and straightforward ❤

  • @randomgamevideos241
    @randomgamevideos241 3 місяці тому

    i agree with you, normally i try to avoid recursion unless it is the only solution i see, i prefer loops over recursions, i can definitely say my code is a mix of all three styles ( when the style is needed ).

  • @Psi141
    @Psi141 3 місяці тому +2

    Underrated af

  • @DavidSosa-n8u
    @DavidSosa-n8u 3 місяці тому

    Love these vids, idk how I stumped upon your account but it’s very helpful

  • @nasccped
    @nasccped 3 місяці тому +1

    Awesome video dude! ❤

  • @DnBComplex
    @DnBComplex 3 місяці тому +1

    Amazing video.

  • @samconnelly7630
    @samconnelly7630 3 місяці тому +2

    Here is my attempt at the functional programming example. I made sure to include the same bug where there was an extra comma after the number. This is in Haskell. EDIT: UA-cam doesn't render code snippets.
    module Main where
    printOutput :: [Int] -> IO ()
    printOutput x = do
    putStrLn $ "The sum of: " ++ (foldl (++) "" $ map (\x -> (show x) ++ ", ") x) ++ "= " ++ (show $ sum x)
    putStrLn $ "The average: " ++ show (toInteger $ floor $ median $ map fromIntegral x)
    median :: Fractional a => [a] -> a
    median x = (sum x) / (fromIntegral $ length x)
    main :: IO ()
    main = printOutput [1,9,2,4,2,5,8,1,4,6]

  • @Nellak2011
    @Nellak2011 3 місяці тому

    --------- My Procedural style: 4 LOC, with mutation and straightforward logic
    const main = () => {
    const nums = std.getInput("enter array of numbers") // or however it is done
    let sum = 0
    for (const num of nums) { sum += num }
    console.log(`Total: ${sum}
    Average: ${sum / nums.length}`)
    }
    --------- My Functional style: 4 LOC, with no mutations and concise logic
    const average = nums => nums.reduce((acc, el) => {sum: acc.sum + el, avg: (acc.sum + el)/nums.length}, {sum: 0, avg: 0})
    const display = ({sum, avg}) => console.log(`Total: ${total}
    Average: ${average}`)
    const main = () => {
    const nums = std.getInput("enter array of numbers") // or however it is done
    display(average(nums))
    }
    --------- My OOP style (I never use it so it may have syntax issues):16 LOC, with mutations and convoluted logic
    class displayNumber {
    let sum, average = 0
    constructor(nums) {
    let newSum = 0
    for (const num of nums) { newSum += num }

    this.sum = newSum
    this.average = newSum / nums.length
    }
    display = () => console.log(`Total: ${this.sum}
    Average: ${this.average}`)
    }
    const main = () => {
    const nums = std.getInput("enter array of numbers") // or however it is done??
    let displayNumber = new displayNumber(nums)
    displayNumber.display()
    }
    ----------
    FP > Procedural > OOP

  • @xzazen
    @xzazen 3 місяці тому +4

    fyi the function PrintNumbers(int i, int max) is not strictly a pure function (it does not give the same output for the same set of inputs) because you have a side-effect - Console.WriteLine() is IO bound and could cause an exception, in C# you probably would have to roll your own IO monad (essentially a container) and return the IO(result) or IO(error) to make it a pure function.
    The benefit is that you can remove stateful exception handling which is outside of the function and have "railway-oriented" exception handling.

    • @CodingWithTom-tn7nl
      @CodingWithTom-tn7nl  3 місяці тому +1

      The point is to use a functional style of programming in your code which has a benefit of making errors easier to find. I've never actually seen IO output fail and throw an exception, so I'm not sure how much benefit you are getting from doing this.

    • @etooamill9528
      @etooamill9528 3 місяці тому

      ​@@CodingWithTom-tn7nl if the program output is piped linux style in another program input and the receiving program crashes, does the output fail if you keep trying to write to it?

    • @lemna9138
      @lemna9138 3 місяці тому

      ​@CodingWithTom-tn7nl surely you've seen a network call or filesystem interaction fail before?

  • @LatticeCodes
    @LatticeCodes 3 місяці тому

    Your visuals are nice, good explanations!

  • @shawn576
    @shawn576 16 днів тому

    Why did you declare average as an integer?

  • @gJonii
    @gJonii 3 місяці тому +3

    Your fp example was oddly made in a way that seems harder to read than the default example everyone gives, where calculatetotal would take two parameters, list of numbers and total. You'd slice the first element off the list, add it to total, and do it like that.
    There's also really no point in using recursion imo, the reason it's popular is because Haskell etc have first-class support for it. Language you used here doesn't have that(was it C#? I didn't recognize it). However, that language likely has built-in reduce-method. Universality of these operations is a big selling point of FP, and by specifically avoiding showcasing it, you're seemingly purposefully trying to make FP seem worse than it is, by doing the example code in bad style, insisting on recursion when it's not really needed, and insisting on not using the universal patterns when universality of those patterns is a big selling point of the language.
    Also, the whole createoutput would've also been able to use the exact same reduce-operator, further showcasing this "simple universal tools serve you often quite well"

    • @CodingWithTom-tn7nl
      @CodingWithTom-tn7nl  3 місяці тому

      Yes it's C#. There are inbuilt functions for what I'm doing, like array.Sum() which, in c#, actually does exactly what I did with the for loop, just in a generic way. I'm trying to explain the concepts of these paradigms and if I just use inbuilt functions without actually showing how they work doesn't explain much.
      You can't always use a built in function for what you're doing and for those situations, in function programming you generally use recursion or lambda expressions. I wanted to use a simple example so most people can understand what's happening, but that also means there are usually inbuilt functions for that.
      The simplest way to write it:
      public static void Main()
      {
      int[] numbers = {1,9,2,4,2,5,8,1,4,6};
      int total = numbers.Sum();
      int average = total / numbers.Length;
      string output = $"The sum of: {string.Join(", ", numbers)} = {total}
      Average = {average}";
      Console.WriteLine(output);
      }
      I gaurantee that in c# array.Sum and string.Join don't follow functional programming principles, so it kind of defeats the point anyway.

    • @gJonii
      @gJonii 3 місяці тому

      @@CodingWithTom-tn7nl Sum is specific-purpose tool. For functional approach using the generic tools like reduce, based on my quick googling, you would use `numbers.Aggregate((acc, x) => acc + x)`(C# seems to have decided to call its version of reduce "Aggregate").
      It's true that you do have that already with Sum-method, which is less interesting, but map, reduce and filter are extremely basic and universal fp tools, which many FP languages do have their own specific syntax for. For C# and such, you often expect them to rather show up as some standard library functions, like here Aggregate. Using them isn't really cheating, it's demonstrating the style that fp encourages and expects, using combinators(like reduce), which get passed as a parameter a function that contains the logic.
      You likely could even implement reduce on your own in a couple of lines? Not sure if C# allows such generic higher order functions, but if it does, that shouldn't be more than one or two lines.
      I'm also not sure you want to use recursion. With Haskell it's a feature of the language, that recursion has excellent support, but languages that don't have that level of support, you probably want to implement the primitives like reduce with loops. That's what Haskell does too, decomposes recursion into loops. If your language doesn't do that, avoiding loops is imo a bit of a cargo cult thing rather than FP thing, at least if performance is a consideration.

    • @gJonii
      @gJonii 3 місяці тому

      To clarify, the point imo is, you want the functional primitives to be performant enough, implemented in whatever works best. These would include tools like map, reduce, filter, and such. After you have these basic tools however, you would not really need loops, since these tools handle whatever use cases you have for looping.

  • @mohanedomer9081
    @mohanedomer9081 3 місяці тому

    man 12:00 is the best :)

  • @Jediahgames
    @Jediahgames 3 місяці тому

    Why the hell would you use Stringbuilder for that?

  • @yes5421
    @yes5421 3 місяці тому

    I’m a freshman going into uni and I’ve studied for the Java oracle certification a couple years ago, so I am familiar with the concepts theoretically however never implemented them into an actual project. What project should I do with Java to be familiar and gain my memory back of Java as I am a bit rusty but remember concepts and am familiar with OOPS programming.

    • @arcurnow
      @arcurnow 3 місяці тому

      Woof, that’s a tricky one. Hopefully someone else can give you a better answer, but I’d say build something you’re interesting in. That’ll help keep you going. Identify a problem and invent a solution. Can be something that’s already been solved a thousand times over, but that doesn’t matter cuz it’s not the point. An example from my own experience. During the COVID lockdown rock climbers couldn’t easily go to the climbing gym to train. I built an app that allowed people to upload pictures of climbs from their gym along with the solution to said climb that other climbers could study and guess the betas (one of the correct routes up the climbing problem). The user could click a hold and define what kind of hold it was (ie right hand starting hold) and if it was a correct part of the beta they could move on to the next climbing move (left heel hook on this hold… on and on with the rest of the moves. All of it was shared and posted in a social media style. It only ever ran locally on my machine but it was interesting and kept me going through the confusing / difficult parts. Maybe thinking in terms of “find a problem and solve it” might get the juices flowing. Good luck young sir!

  • @SchoolyB
    @SchoolyB 3 місяці тому +2

    Procedural FTW

  • @paulzupan3732
    @paulzupan3732 3 місяці тому +4

    The object-oriented example is not very good. I can't believe that you coupled the notion of summing numbers to the number data itself. I would have created a NumberSumCalculator class which takes in a NumberArray along with an implementation of a NumberAdder interface. What if you wanted different strategies for adding numbers together? After all, there are many different ways to combine two numbers, and you want your code to be flexible, maintainable, and readable. You'd probably also want a NumberAverageCalculator interface, since there are multiple ways to find the average of a list of numbers.
    Not to mention that you coupled creating the output with the number data as well. I think the best solution would be a NumberDataOutputWriter class which takes in some sort of Writer interface (you might not want to print it to standard out, you could print to a file, write to a string, et cetera), as well as an object that implements both the NumberSumCalculator and NumberAverageCalculator interfaces so that you can get at that data.
    Overall, your solution is not scalable, readable, maintainable, flexible, or robust. 0/10.
    (edit) I’m sorry if this sounded too serious, I’m just kidding. I really enjoyed the video.

  • @nartoomeon9378
    @nartoomeon9378 3 місяці тому +1

    hmm... 6:35 there's something wrong here, because functional programming don't require immutable vars. Almost all functional lang-s are statically typed, but that doesn't mean they have immutable vars. The key feature is *pure functions* , higher order functions and possibly, monads. Pure function-is a function without side effects, in other words, same input-same output. Purity gives a more readable code, where user clearly see all possible outputs of a function. In the first example 6:58 we have a mutable variable, but it exist in separate name scope, so the function is pure! it doesnt change anything from outer scope.

  • @SirRichard94
    @SirRichard94 3 місяці тому

    Your FP example and conclusions are not very good. The cost of recursion can be minimized with language support of tail end optimization. And you didnt show some of the most important features which hare first class functions, lambdas and closures which would be useful for this program. Sum could be a reduce operation. You'd likely separate the writing away from the output function and also make it with a reduce.
    Something kind of like this.
    Pseudocode:
    let sum = reduce(numbers, 0, +)
    let avg = sum / count(numbers)
    let output = reduce(numbers, "[ " , (a, b) => a ++ b ++ ", ") ++ "] average = " ++ to_string(avg) ++ ", sum = "++ to_string(sum) ++ "/n"
    print(output)