Interfaces vs Abstract Classes

[)roi(];19001352 said:
Sure...it's YOLO scenario:

Btw, my comments (and that of my MyBB peers) aren't meant to criticise, rather to share experience or to encourage you to consider alternatives.

Put it this way, I've never felt discouraged and wanting to quit, rather the comments from every single one of you here always leave us newbies here feeling challenged and wanting to do better. So thank-you!

I referred earlier to a "either monad with bind"; which as a basis deals with outcomes, for example:
  • Success
  • ...or, Failure
...depending on the outcome, you could either continue the process chain or terminate (i.e. for recourse at the point of initiation).

Bind in short ties up the input and outputs i.e. 1 function feeds into another in a chain of events. If any link (function) fails; the link is terminated; however the cause is always captured and relayed back to initiating event.

For example:
PHP:
var a = function1(arg1); 
var b = function2(a)
....
var z = function27(y)

We call function1and store the result in "a"; and then call function2 and pass in the function 1 result: "a". "a" could be as example:
  • a reference to an instance,
  • value
  • an error code.
Either way if function2 is dependent on the result of function1; "a" should ideally be sufficient for function2 to determine is it can safely proceed or whether it needs to abort and relay the failure back to the originating event.

Naturally all of this can be expressed i.t.o. if-elseif-else statements.

Bind FYI is a similar approach to the if-elseif-else one, except that it follows a more declarative and terse style. The Either type btw is just an approach to encapsulate two possible outcomes, e.g. Success or Failure. Success would be what the next function in the call chain would require, whereas Failure would be an instruction to that function to bypass the processing in order to return the failure up the call stack.

Similarly you'll find code that uses exceptions for this purpose; but in practice that can easily lead to more try {} catch {} wrappers that ultimately just ignore the underlying fragility. Worse you have an implicit result i.e. your function shows it returns nothing; void (an Action), however a re-throw is also a result, except it's anything but explicit.

Using a Either style monad for the result type would mean your functions are modelled more like this:
PHP:
private static Result<Success, Failure> function1(InputType input) { }
private static Result<Success, Failure> function2(Result<Success, Failure> input) { }

// this is called as follows

var a = function1(inputValue)
               .bind(function2)
               .bind(function3)
               .bind(function4);
We start with function1, and bind into function2 with the result from function1. function2 then has internal code to explicitly deal with deal with Success or Failure; Failure is a simple bypass, simply returning the input (i.e. the 1st issue), ultimately leading to that Failure being returned up the call stack to initiating call: "a" would either be the result of a Success or Failure.

Let me know if you'd like to see how to implement this in C#. Not that much code is required.

This, is incredibly helpful. What is happening at the moment is the failure is simply making it's way back down the chain to the source and not being dealt with. And if I have multiple Inserts or Selects, each call is simply throwing an error at the source (DAL), going back down the chain ending up with something like a DataSet which is now equal to NULL over and over. Does that make sense?

Thanks for the advice here, I am going to need to rework error capturing right through.
 
Put it this way, I've never felt discouraged and wanting to quit, rather the comments from every single one of you here always leave us newbies here feeling challenged and wanting to do better. So thank-you!



This, is incredibly helpful. What is happening at the moment is the failure is simply making it's way back down the chain to the source and not being dealt with. And if I have multiple Inserts or Selects, each call is simply throwing an error at the source (DAL), going back down the chain ending up with something like a DataSet which is now equal to NULL over and over. Does that make sense?

Thanks for the advice here, I am going to need to rework error capturing right through.
If you got the time, then from a learning perspective I'd suggest you explore multiple options in order to weigh up the pros and cons for yourself.

For example:
  1. You could rethrow the Exceptions up the call stack:
    • The idea being that you would deal with these later on.
    • The problem with this, is that on the surface your function appears to be a simple action (i.e. with no return value or obvious dependency), however we shouldn't forget that a rethrow is also a return type; a not very obvious one; arguably it separates the problem from the recovery.
  2. Secondly you could add an explicit return type, for example:
    • Predicate function: boolean value; within the function you decided on whether the return value should be true or false. For example: hasQueryExecuted(...)
    • Alternatively in a multi step process, you could follow a more historical approach; returning an instance reference; where a null reference would generally indicate failure. The biggest and historical problem here is that you could easily forget to check for a null for all conditions leading up to this.
  3. The third approach is the one I described, where we use a result type that has either a success or failure branch; The benefit of this approach is that we are always forced, to deal with a success or failure. i.e. it's not so easy to just inadvertently bypass like you could with a null. Other plus point is that the use is quite a lot more like declarative programming.
FYI: I've been working on trying to simplify an example of the third approach for a student I tutor in Java. As example, this is the entire process call to retrieve a multi day weather report for a city (using the openweathermap api)
PHP:
Result<Forecast, String> weatherReport = getWeatherFor(cityId)
   .bind(Web::connectToURL)
   .bind(Web::validateHTTPResponse)
   .bind(Web::getJSONFromInputStream)
   .bind(Weather::deserializeJSONWeather);

Here's the code for validateHTTPResponse function:
PHP:
  private static Result<URLConnection, String> validateHTTPResponse(Result<URLConnection, String> lastOpResult) {
    if (!lastOpResult.isSuccess()) { return lastOpResult; }
    URLConnection connection = ((Success<URLConnection, String>) lastOpResult).value;
    if (!(connection instanceof HttpURLConnection)) { return new Failure<URLConnection, String>("Unknown error: result not instanceof HttpURLConnection"); }
    HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
    try {
      if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { return lastOpResult; }
      return new Failure<URLConnection, String>(extractJSONFromStream(httpURLConnection.getErrorStream()));
    } catch (Exception e) {
      return new Failure<URLConnection, String>(e.getMessage());
    }
  }

Note in particular, we start the function with a check to see if the last operation was successful, if it's not we skip this step and return the failure.
PHP:
if (!lastOpResult.isSuccess()) { return lastOpResult; }
Secondly we contain the exception within the function, returning only the pertinent information. FYI, in this example I'm simply returning a string for Failure, however it can easily be converted to return a reference to an Exception instance.
 
By this time Solarion does not know where to hold and where to let go. I think Spacerat is wrong, but if he is not then I'm confused as well.


The ONLY reason why you catch the exception at this level is to implement transaction control. You are intercepting the exception propagating up the call stack in order to perform an essential function i.e. transaction rollback. If it wasn't for the need to perform the rollback, you wouldn't catch the exception here. If that is ALL you want to do then yes you don't need to rethrow the exception.

But if you don't rethrow the exception, once the method returns to the calling method, the calling method had no idea there was an exception (because the called method swallowed it) and would carry on none the wiser. Not really what you want. Sure you can return an error code but that is so 80's.

If you want to handle the exception at a higher level e.g. map the exception message based on the exception type to a user-friendly message and display an error dialog then you have to rethrow. Rethrowing to simply branch is wrong yes. But it depends on what you want to do.
 
Last edited:
[)roi(];19009766 said:
For example:
  1. You could rethrow the Exceptions up the call stack:
    • The idea being that you would deal with these later on.
    • The problem with this, is that on the surface your function appears to be a simple action (i.e. with no return value or obvious dependency), however we shouldn't forget that a rethrow is also a return type; a not very obvious one; arguably it separates the problem from the recovery.


  1. Yes, and this is why most API's document any exception types that the method could throw and why. The .NET Framework being one example
 
Further to my previous post on exception handling. You guys need to read up on Exception Handling Strategies. It is a thing ..:whistle:

Exception handling strategies include:
- Displaying an error dialog
- Logging the exception to a file/database/trace logger/JIRA/whatever
- Mapping the exception to another
- Wrapping the original exception into another to rethrow

or any combination of the above.

However, these strategies cannot be implemented at the level where it was caught. It has to be handled at a higher level. This is the reason you rethrow so that the exception can bubble up the stack after interception so that the handling strategy can be implemented.
 
The ONLY reason why you catch the exception at this level is to implement transaction control. You are intercepting the exception propagating up the call stack in order to perform an essential function i.e. transaction rollback. If it wasn't for the need to perform the rollback, you wouldn't catch the exception here. If that is ALL you want to do then yes you don't need to rethrow the exception.

But if you don't rethrow the exception, once the method returns to the calling method, the calling method had no idea there was an exception (because the called method swallowed it) and would carry on none the wiser. Not really what you want. Sure you can return an error code but that is so 80's.

If you want to handle the exception at a higher level e.g. map the exception message based on the exception type to a user-friendly message and display an error dialog then you have to rethrow. Rethrowing to simply branch is wrong yes. But it depends on what you want to do.

Ok, I'm with you. It does seem like proper practice.
 
Yes, and this is why most API's document any exception types that the method could throw and why. The .NET Framework being one example
Uh huh... but that leads to a lot of code like this:
PHP:
public static void FunctionXYZ(string[] args)
{
    try {
        // Main body of a function (i.e. wrap everything)
    } catch (Exception e) {
        Console.WriteLine(e.Message);
    }
}
 
Further to my previous post on exception handling. You guys need to read up on Exception Handling Strategies. It is a thing ..:whistle:

Exception handling strategies include:
- Displaying an error dialog
- Logging the exception to a file/database/trace logger/JIRA/whatever
- Mapping the exception to another
- Wrapping the original exception into another to rethrow

or any combination of the above.

However, these strategies cannot be implemented at the level where it was caught. It has to be handled at a higher level. This is the reason you rethrow so that the exception can bubble up the stack after interception so that the handling strategy can be implemented.
Maybe you're the missing the obvious... Either monads with bind do exactly that, however in a process the handling is far more explicit than just rethrows and loggers + it doesn't prevent the use of loggers or relaying of the Exception instance for a rethrow (it is after all just a reference).

Btw the way the .NET framework certainly doesn't restrict e.g. here's the same approach in F#
http://fsharpforfunandprofit.com/posts/recipe-part2/
 
Last edited:
[)roi(];19009892 said:
Maybe you're the missing the obvious... Either monads with bind do exactly that, however in a process the handling is far more explicit than just rethrows and loggers + it doesn't prevent the use of loggers or relaying of the Exception instance for a rethrow (it is after all just a reference).

Not sure whyyou come with monads. We talking basic C# code here to help OP. You are confusing him as he seems to be relatively new...
 
Last edited:
Not sure whyyou come with monads. We talking basic C# code here to help OP. You are confusing him as he seems to be relatively new...
It's the same objective:
  • Oldest approach to the problem was integer return values.
  • OOP introduced Exception handling.
  • Functional Programming (FP) introduced Either monad.

Nothing in the .NET framework specifically limits the approach; plus most of the new additions to both Java and C# are FP related, similar case for e.g. Javascript

Plus what's so NOT BASIC about an abstract class with two sub types; here's the Result types (Success or Failure) in C#.

/Edit : Updated for C# equivalent

PHP:
public abstract class Result<S, F>
  {
    public abstract Result<O, F> bind<O>(Func<Result<S, F>, Result<O, F>> function);
    public abstract Boolean isSuccess();
    public abstract Object get();
  }

  public class Success<S, F> : Result<S, F>
  {
    public S Value;

    public Success(S Value)
    {
      this.Value = Value;
    }

    public override Result<O, F> bind<O>(Func<Result<S, F>, Result<O, F>> function)
    {
      return function(this);
    }

    public override Boolean isSuccess()
    {
      return true;
    }

    public override Object get()
    {
      return this.Value;
    }
  }

  public class Failure<S, F> : Result<S, F> 
  {
    public F Value;

    public Failure(F Value)
    {
      this.Value = Value;
    }

    public override Result<O, F> bind<O>(Func<Result<S, F>, Result<O, F>> function)
    {
      return new Failure<O, F>(this.Value);
    }

    public override Boolean isSuccess()
    {
      return false;
    }

    public override Object get()
    {
      return this.Value;
    }
  }

Nothing complicated about that -- it's really just a different approach to the same problem.
 
Last edited:
[)roi(];19009924 said:
It's the same objective:
  • Oldest approach to the problem was integer return values.
  • OOP introduced Exception handling.
  • Functional Programming (FP) introduced Either monad.

Nothing in the .NET framework specifically limits the approach; plus most of the new additions to both Java and C# are FP related, similar case for e.g. Javascript

It's just a different approach to the same problem.

Agreed, but with all due respect, 'polluting' the thread with FP concepts is confusing OP and not helping him. FP is also rather off-topic in this thread. Your contribution is definitely respected, but let's help OP with his problem.
He seems to be grappling with basic error handling / Exception handling / abstraction etc. Getting him to grasp and adopt FP concepts is an initiative of another magnitude.
 
Agreed, but with all due respect, 'polluting' the thread with FP concepts is confusing OP and not helping him. FP is also rather off-topic in this thread. Your contribution is definitely respected, but let's help OP with his problem.
He seems to be grappling with basic error handling / Exception handling / abstraction etc. Getting him to grasp and adopt FP concepts is an initiative of another magnitude.
Doubtful... studies tend to confirm exact the opposite. New developers are able adopt these ideas far easier than old programmers.

Dependency injection, Inversion of Control, injection frameworks, ... were also at a point in time new approaches to similar issues; yet you'd probably argue that's in scope.

Plus where have you been for the last decade or so. C# started with FP in C# 3.5 i.e. 2007... so FP isn't quite so new or off the topic as you say it is.
 
[)roi(];19009978 said:
Doubtful... studies tend to confirm exact the opposite. New developers are able adopt these ideas far easier than old programmers.

Dependency injection, Inversion of Control, injection frameworks, ... were also at a point in time new approaches to similar issues; yet you'd probably argue that's in scope.

Plus where have you been for the last decade or so. C# started with FP in C# 3.5 i.e. 2007... so FP isn't quite so new or off the topic as you say it is.

New developers adopt it but ask them to explain it...
"Guys we should do DI"
Why?
"Because it's good practice"
Yes but why?

They usually abandon it after that.
 
[)roi(];19009978 said:
Doubtful... studies tend to confirm exact the opposite. New developers are able adopt these ideas far easier than old programmers.

Dependency injection, Inversion of Control, injection frameworks, ... were also at a point in time new approaches to similar issues; yet you'd probably argue that's in scope.

Plus where have you been for the last decade or so. C# started with FP in C# 3.5 i.e. 2007... so FP isn't quite so new or off the topic as you say it is.

Sigh...

If OP wants to make the jump FP then great you can help him.
 
New developers adopt it but ask them to explain it...
"Guys we should do DI"
Why?
"Because it's good practice"
Yes but why?

They usually abandon it after that.

If adopting a new approach is purely academic, then yes they would likely abandon it, I feel that if a dev experiences the benefits first-hand in terms of code quality, extensibility, etc etc then they are far more likely to pursue it further and entrench those approaches in their thinking.
 
New developers adopt it but ask them to explain it...
"Guys we should do DI"
Why?
"Because it's good practice"
Yes but why?

They usually abandon it after that.
Is that a reflection of the solution or mentor...


Sigh...

If OP wants to make the jump FP then great you can help him.
It's not about jumping either way; as always there are many ways to "skin a cat"; appreciating the difference is important.
Remember your bias for one doesn't make it an absolute + please don't tell me you've never used LINQ, Lambdas, Tuples, ... or in the broader sense haven't had the need to box more than one outcome without the use of null returns or exceptions.
 
[)roi(];19010182 said:
Is that a reflection of the solution or mentor...

Just because the younger programmers take to something doesn't mean they actually understand it. I prefer to term them hype developers.
 
Just because the younger programmers take to something doesn't mean they actually understand it. I prefer to term them hype developers.
OOP is not easier than FP -- so not understanding, appreciating or justifying something is not something new.

Copy/Paste programmers are bad irrespective of language or paradigm; and if that's what an education platform is delivering then question the quality of the tutoring. Our Gov, for example: questioned the merit of mathematical theory, and we've seen that outcome.

Programming is no different; soft coating knowledge always lead to an inferior result + most bias is from the older generation, much like my gran refused to ever use a computer, we now have programmers arguing why alternative approaches are somehow bad, or too complicated.

Personally I just think that's a reflection of the the anti-this progenitor's own deficiencies.
 
Last edited:
One might say, the conversation has become too abstract, and we should interface with the OP.
 
Top
Sign up to the MyBroadband newsletter
X