16

If I want to program in a "functional" style, with what would I replace an interface?

interface IFace
{
   string Name { get; set; }
   int Id { get; }
}
class Foo : IFace { ... }

Maybe a Tuple<>?

Tuple<Func<string> /*get_Name*/, Action<String> /*set_Name*/, Func<int> /*get_Id*/> Foo;

The only reason I'm using an interface in the first place is because I want always want certain properties/methods available.


Edit: Some more detail about what I'm thinking/attempting.

Say, I've got a method which takes three functions:

static class Blarf
{
   public static void DoSomething(Func<string> getName, Action<string> setName, Func<int> getId);
}

With an instance of Bar I can use this method:

class Bar
{
   public string GetName();
   public void SetName(string value);

   public int GetId();
}
...
var bar = new Bar();
Blarf.DoSomething(bar.GetName, bar.SetName, bar.GetId);

But that's a bit of a pain as I have to mention bar three times in a single call. Plus, I don't really intend for callers to supply functions from different instances

Blarf.DoSomething(bar1.GetName, bar2.SetName, bar3.GetId); // NO!

In C#, an interface is one way to deal with this; but that seems like a very object-oriented approach. I'm wondering if there's a more functional solution: 1) pass the group of functions together, and 2) ensure the functions are properly related to each other.

5
  • You wouldn't. Interfaces for datatypes are perfectly fine (though you would favor immutable objects).
    – Telastyn
    Commented Mar 3, 2013 at 4:21
  • 1
    Chapter 2 of the SICP is pretty much about this.
    – user16764
    Commented Mar 3, 2013 at 4:37
  • 9
    After rereading your question, I'm curious what specific functionality you're trying to accomplish? What you appear to be asking for is how to do oo style side-effectful programmin against an instance in a functional style, which doesn't make sense.. Commented Mar 3, 2013 at 4:53
  • The answer would be language-dependent. In Clojure you can use clojure.org/protocols, where the only soft area is the types of parameters that the functions must operate on - they are an object - that is all you know.
    – Job
    Commented Mar 4, 2013 at 5:22
  • 1
    Make it simple: a struct containing those method pointers, plus a function to initialize it from an object instance. Why Haskell? ;)
    – mlvljr
    Commented Aug 6, 2013 at 20:44

6 Answers 6

9

Don't treat functional programming as a thin veneer over imperative programming; there's much more than just a syntactic difference.

In this case, you have a GetID method, which implies uniqueness of objects. This is not a good approach to writing functional programs. Perhaps you could tell us the problem you are trying to solve and we could give you more meaningful advice.

2
  • 1
    @Ðаn Is that really a Firefox (film) quote (because that's awesome if it is)? Or is it used somewhere else?
    – icc97
    Commented May 18, 2018 at 8:00
  • 2
    Where as I agree it's a complete paradigm shift from Imperitive to Functional Programming, there are many orders of magnitude more lines of code written in an imperitive manner. So a lot more of the corner cases written for huge systems will have been found with imperitive programming. There are lots of good practices in imperitive programming and knowing if those skills can be translated or if they are a non-issue in FP is a worthy question. It is completely possible to write horrible code in FP, so these kind of questions should highlight the good parts of FP too.
    – icc97
    Commented May 18, 2018 at 8:06
11

Haskell and it's derivatives have typeclasses which are similar to interfaces. Though it sounds like you're asking about how to do encapsulation, which is a question regarding type systems. The hindley Milner type system is common in functional languages, and it has data types that do this for you in varying fashion across languages.

1
  • 6
    +1 for typeclasses - the main difference between a Haskell typeclass and a Java interface is that the typeclass is associated with the type after both are separately declared. You can use an old type through a new "interface" as easily as you can use an old "interface" to access a new type. For data hiding, you hide the implementation of the type in a module. At least according to Bertrand Meyer of Eiffel fame, an OOP class is a kind of module.
    – user8709
    Commented Mar 3, 2013 at 16:31
5

There are a few ways to allow a function to deal with multiple inputs.

First and most common: Parametric Polymorphism.

This lets a function act on arbitrary types:

--Haskell Example
id :: a -> a --Here 'a' is just some arbitrary type
id myRandomThing = myRandomThing

head :: [a] -> a
head (listItem:list) = listItem

Which is nice, but doesn't give you the dynamic dispatch that OO interfaces have. For this Haskell has typeclasses, Scala has implicits, etc

class Addable a where
   (<+>) :: a -> a -> a
instance Addable Int where
   a <+> b = a + b
instance Addable [a] where
   a <+> b = a ++ b

--Now we can get that do something similar to OO (kinda...)
addStuff :: (Addable a) => [a] -> a
-- Notice how we limit 'a' here to be something Addable
addStuff (x:[]) = x
addStuff (x:xs) = x <+> addStuff xs
-- In better Haskell form
addStuff' = foldl1 <+>

Between these two mechanisms, You can express all sorts of complex and interesting behaviors on you're types.

1
  • 1
    You can add sintax highlighting hints when the language in the answer doesn't match the language in the question. See my suggested edit for example.
    – hugomg
    Commented Mar 4, 2013 at 16:00
1

The basic rule-of-thumb is that in FP programming functions do the same job as objects do in OO-programming. You can call their methods (well, the "call" method anyway) and they respond acording to some encapsulated, internal rules. In particular, every decent FP language out there lets you have "instance variables" in your function with closures / lexical scoping.

var make_OO_style_counter = function(){
   return {
      counter: 0
      increment: function(){
          this.counter += 1
          return this.counter;
      }
   }
};

var make_FP_style_counter = function(){
    var counter = 0;
    return fucntion(){
        counter += 1
        return counter;
    }
};

Now the next question is what do you mean by an interface? One approach is using nominal interfaces (it conforms to the interface if it says it does so) - this one usually depends a lot on what language you are using so lets leave it for latter. The other way to define an interface is the structural way, seeing what parameters thing receive and return. This is the sort of interface you tend to see in dynamic, duck-typed languages and it fits very well with all of FP: an interface is just the types of the input parameters to our functions and the types they return so All functions matching the correct types fit the interface!

Therefore, the most straightforward way of representing an object matching an interface is to simply have a group of functions. You usually get around the uglyness of passing the functions separately by packing them in some sort of record:

var my_blarfable = {
 get_name: function(){ ... },
 set_name: function(){ ... },
 get_id:   function(){ ... }
}

do_something(my_blarfable)

Using naked functions or records of functions will go a long way in solving most of your common problems in a "fat-free" manner without tons of boilerplate. If you need something more advanced than that, sometimes languages give you extra features. One example people mentioned is Haskell type classes. Type classes essentially associate a type with one of those records of functions and lets you write things so the dictionaries are implicit and get automatically passed to inner functions as appropriate.

-- Explicit dictionary version
-- no setters because haskell doesn't like mutable state.
data BlargDict = BlargDict {
    blarg_name :: String,
    blarg_id   :: Integer
}

do_something :: BlargDict -> IO()
do_something blarg_dict = do
   print (blarg_name blarg_dict)
   print (blarg_id   blarg_dict)

-- Typeclass version   
class Blargable a where
   blag_name :: a -> String
   blag_id   :: a -> String

do_something :: Blargable a => a -> IO
do_something blarg = do
   print (blarg_name blarg)
   print (blarg_id   blarg)

One important thing to note about typeclasses however is that the dictionaries are associated with the types, and not with the values (like what happens in the dictionary and OO versions). This means you that the type system doesn't let you mix "types" [1]. If you want a list of "blargables" or a binary function taking to blargables then typeclasses will constrain everything to be the same type while the dictionary approach will let you have blargables of different origins (which version is better depends a lot in what you are doing)

[1] There are advanced ways to do "existential types" but its usually not worth the trouble.

0

I think it's going to be language specific. I come from a lispy background. In many cases interfaces with state break the functional model to a degree. So CLOS, for example, is where LISP is less functional and closer to an imperative language. Generally, required function parameters combined with higher level methods are probably what you're looking for.

;; returns a function of the type #'(lambda (x y z &optional a b c)

(defun get-higher-level-method-impl (some-type-of-qualifier) 
    (cond ((eq 'foo) #'the-foo-version)
          ((eq 'bar) #'the-bar-version)))
0

More or less language-specific, I'd say. In Elixir, modules can choose to adopt (implement) the same behavior (interface).

Behaviors define "callback"s, that adopters should implement:

If a module adopting a given behaviour doesn’t implement one of the callbacks required by that behaviour, a compile-time warning will be generated.

Here's an example taken from the Elixir docs that tries to demonstrate the concept by defining a Parser behavior and two adopters for JSON and Yaml.

defmodule Parser do
  @callback parse(String.t) :: {:ok, term} | {:error, String.t}

  @callback extensions() :: [String.t]
end

defmodule JSONParser do
  @behaviour Parser

  @impl Parser
  def parse(str), do: {:ok, "some json " <> str} # ... parse JSON

  @impl Parser
  def extensions, do: ["json"]
end

defmodule YAMLParser do
  @behaviour Parser

  @impl Parser
  def parse(str), do: {:ok, "some yaml " <> str} # ... parse YAML

  @impl Parser
  def extensions, do: ["yml"]
end

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.