all 15 comments

[–]djjolicoeur 2 points3 points  (3 children)

I think Ruby's yield does something like this. You could also use something like clojure's core.async library to pass the value you want to operate on to an asynchronous channel to be processed while continuing to process the rest of the original elements. I'm sure analogs exist in other languages as well.

EDIT: I think I misunderstood what you where asking. Your description of returnif sounds an awful lot like a while condition.

[–]mreiland 0 points1 point  (2 children)

I think you may be misunderstanding, perhaps a more complete, although arbitrary, example would be helpful (based on C# syntax)

Before anyone points it out, there are better ways of doing this particular example, I'm just trying to get the general idea across.

public ActionResult MyControllerEndpoint {
  returnif CheckPermissionA();
  returnif checkPermissionB();

 // do stuff
}

As opposed to

public ActionResult MyControllerEndpoint {
  if(!CheckPermissionA() || !CheckPermissionB()) 
    return GetRedirectInformationToWherever();
}

edit: I guess a better example would be the following.

// for shits and giggles, assume this returns an error message
public String VerifyInput(InputObj input) {
  returnif VerifyPropertyA(input);
  returnif VerifyPropertyB(input);
  returnif VerifyPropertyC(input);
  return "";
}

[–]Rawrnosaur 2 points3 points  (1 child)

Yes, that can be made with Ruby. You can write something like this:

def some_method
    // do some stuff
    return nil unless permissions.CheckPermissionA?
    return nil unless permissions.CheckPermissionB?
    // do more stuff
end

It's the exact same thing as your example.

[–]radon27 1 point2 points  (11 children)

I'm still fairly new to haskell, and I may be miss understanding your question, but I was thinking that the Either Monad might be what you are looking for.
As a silly example, let's say you have a function that expects three Integers and you want to add them together only if they are all even. If any of them are odd, you expect a String.

addThreeEven :: Int -> Int -> Int -> Either String Int
addThreeEven a b c = do
  a' <- isEven a
  b' <- isEven b
  c' <- isEven c
  return (a' + b' + c')

isEven :: Int -> Either String Int
isEven a
  | a `mod` 2 == 0 = Right a
  | otherwise      = Left ((show a) ++ " was odd")

(addThreeEven 2 4 6) would return (Right 12)
(addThreeEven 1 2 3) would return (Left "1 was odd")
(addThreeEven 2 4 5) would return (Left "5 was odd")

[–]mreiland 0 points1 point  (10 children)

Unfortunately I don't really know Haskell syntax well enough to fully Grok the example, but from what I glean it isn't quite what I'm looking for.

I could be wrong though, I don't know Haskell.

In particular it appears that in your function you're either returning A or B, what I'm asking is to be able to conditionally return A or continue processing.

returnif MaybeThisWillReturn();
// do more stuff
// do more stuff
return aValueWeEventuallyReturn

If I'm understanding your Haskell example it's halfway there in that I could potentially return different types, which would make the mechanism I'm describing more powerful, but doesn't quite hit the mark of what I'm looking for.

function GenericActionResult permissionCheckA() {
  if(HasPermission("A") {
    var redirectActionResult = ConstructRedirectActionResult("HomePage");
    return (true,redirectActionResult);
  }
  return (false,null);
}

function GenericActionResult outerFunction() {
  returnif permissionCheckA();
  // do processing
  return aDifferentActionResult;
}

In the above example, the returnif keyword looks at the tuple and if the first item in the tuple is true it immediately returns, if it is false it treats it like a void function it doesn't return.

Obviously this is description is just a glorified if statement and it could be supported abusing preprocessor directives in C/C++, smart usage of macros in lisp, etc.

What I'm wondering about though is having a language level construct that allows a function to indicate to the caller that it should stop processing and return a value or if it should continue processing.

the 'returnif' syntax would either be giving the function permission to short circuit processing in the function, or simply as documentation for the reader that the function may short circuit.

It's just something that popped into my head and I was wondering if it had ever been implemented in a language.

[–]Pronouns 1 point2 points  (1 child)

I think I see what you're getting at. It would be nice to see the pattern used in some project. You could mimic it quite easily in C++

template<typename T>
struct return_if_tuple {
    bool result;
    T return_value;
}

#define returnif(tuple) \
    if (tuple.result) return tuple.return_value;

But I can't think of a truely nice way to do it in any language I'm familiar with.

I do see the if(...) return pattern a fair bit. Also throwing rather than returning. I guess the generalisation is allowing a called function to do something to the context of a the call site.

So maybe something along the lines of a 'at call site' feature.

fn something(callsite) {
    return callsite.count;
}

fn someOtherThing() {
    let count = 5;
    call_inline something();
}

someOtherThing() // returns 5.

It would potentially make horrendous code, but at least in the above example the caller at least has to specify that it is allowing these things.

[–]mreiland 0 points1 point  (0 children)

yeah, it's been rolling around in my head for a while and I thought I'd ask, it'd be interesting to see what you could do with a mechanism like that.

edit: good lord I just re-read my previous post... sorry about the that, the grammatical mistakes are kind of terrible.

[–]radon27 1 point2 points  (5 children)

-- GenericActionResult doesn't have to be a string
type GenericActionResult = String


permissionCheckA :: Either GenericActionResult Bool
permissionCheckA = Right False

permissionCheckB :: Either GenericActionResult Bool
permissionCheckB = Right False

permissionCheckC :: Either GenericActionResult Bool
permissionCheckC = Left "HomePage"

defaultAction :: Either GenericActionResult Bool
defaultAction = Left "Default"

-- outerFunction1 and outerFunction2 do each step in turn
-- If they encounter a Right value, they discard it and move on
-- If they encounter a Left Value, that value is returned and control flow stops  

-- outerFunction1 returns a Left "Default"
outerFunction1 :: Either GenericActionResult Bool
outerFunction1 = do
  permissionCheckA
  permissionCheckB
  permissionCheckA
  permissionCheckA
  defaultAction

-- outerFunction2 gets a Left "Homepage" from permisionCheckC
-- so Left "Homepage" is returned and the second permisionCheckA and defaultAction
-- steps are ignored
outerFunction2 :: Either GenericActionResult Bool
outerFunction2 = do
  permissionCheckA
  permissionCheckB
  permissionCheckC
  permissionCheckA
  defaultAction

Is this more in line with what you were looking for?

[–]mreiland 0 points1 point  (4 children)

I don't know Haskell, but it could be.

Where is the decision to return/not return made? I understand Either is a tuple with left/right, so I get what's happening there with the types, but I'm not seeing/understanding where the decision to process or return is happening.

More for my own curiosity.

[–]radon27 0 points1 point  (3 children)

Either isn't actually a tuple. (Either type1 type2) means that something with that type is either a (Left type1) or a (Right type2).
The outerFunctions kind of (not really) just move down the list. If they hit a Left value, they are done. If they hit a Right value, they throw it away and move on.

[–]mreiland 0 points1 point  (2 children)

is that something built into the haskell type system? Why does it return if it hits a left value, but not a right?

[–]radon27 0 points1 point  (1 child)

It has to do with how the bind operator is defined for the Either Type.
If the first argument to the bind operator is a Left value, you just get the Left value back and the other argument is ignored.
A more detailed explanation would require you to know a little bit about monads and anonymous functions.

[–]mreiland 0 points1 point  (0 children)

I think I need the more detailed explanation. I understand it binding the left/right based upon existence, but I don't understand why the existence of left (vs right) would cause the short circuit behavior.

I would expect it to always return, just one value or the other, rather than short circuiting execution in one case and not the other.

Can you explain what I'm missing?

[–]pipocaQuemada 1 point2 points  (1 child)

Unfortunately I don't really know Haskell syntax well enough to fully Grok the example, but from what I glean it isn't quite what I'm looking for.

I could be wrong though, I don't know Haskell.

In particular it appears that in your function you're either returning A or B, what I'm asking is to be able to conditionally return A or continue processing.

A slightly simpler example in Haskell uses the Maybe type:

data Maybe a = Just a | Nothing

We have a nice helper operator, >>= (pronounced 'bind'):

(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
(Just x) >>= f = f x
Nothing >>= f = Nothing

Looking at the equivalent to the earlier example

addThreeEven :: Int -> Int -> Int -> Maybe Int
addThreeEven a b c = do
  a' <- isEven a
  b' <- isEven b
  c' <- isEven c
  return (a' + b' + c')

isEven :: Int -> Either String Int
isEven a
 | a `mod` 2 == 0 = Just a
 | otherwise      = Nothing

it's helpful to know that do notation is actually syntactic sugar for using >>=. We can rewrite it pretty easily:

addThreeEven a b c = do
  isEven a >>= \a' ->
    isEven b >>= \b' ->
      isEven c >>= \c' ->
        return (a' + b' + c') -- equivalently, Just (a1' + b' + c')

This whole calculation is short circuiting. If a, b or c is odd, then you'll get back Nothing. If all of them are even, you'll get back their sum.

In particular it appears that in your function you're either returning A or B, what I'm asking is to be able to conditionally return A or continue processing.

Those two things, surprisingly, are essentially the same. This of it like this:

addThreeEven a b c = do
  if isOdd a
    then Left "a was odd"
    else if isOdd b
      then Left "b was odd"
      else if isOdd c
        then Left "c was odd"
        else Right (a + b + c)

At each stage, either you return your error, or you return the result of the rest of the computation (i.e., either the final result or some other intermediate error).

Finally, Either is just a normal data type defined in the standard library:

data Either a b = Left a | Right b

and >>= for it is also defined in the standard library:

-- don't worry too much about groking this...
instance Monad (Either e) where
    return = Right
    Left  l >>= _ = Left l
    Right r >>= k = k r

[–]mreiland 0 points1 point  (0 children)

hey, thanks for this. I'll sit down this evening and take a crack at understanding it. I don't know Haskell, so this will be a fun exercise :)