Aprender diferencias fundamentales entre la programación funcional y la programación orientada a objetos

ItamarG3 09/09/2017. 11 answers, 7.339 views
self-learning object-oriented-paradigm functional-programming

He estado tratando de aprender las diferencias entre la programación funcional y OOP, pero no puedo encontrar una comparación de los dos.

Una búsqueda de Google no produce algún gráfico o tabla que muestre dicha comparación.

De la búsqueda incierta de google, he llegado a esto: OOP mantiene las acciones y los datos encapsulados en los objetos, la programación funcional separa los dos.

Pero eso realmente no da una comparación útil de usecases para cada uno.

Por lo tanto, mi pregunta es ¿dónde puedo encontrar una comparación completa entre los dos, que puede explicar qué se debe utilizar para algunos tipos de tareas \ proyectos? Estoy buscando alguna explicación \ comparación de varios aspectos de estos paradigmas.

Los tipos de proyectos o tareas a las que me refiero son variados, pero pueden clasificarse en: Administración de equipos (similar a lo que permiten los usuarios en los navegadores) y Utilidades (conversión de unidades, shell personalizado).

(los recursos fuera del sitio se consideran una respuesta, así como las respuestas que dan tal comparación sin un recurso fuera del sitio)

5 Comments
2 Michael0x2a 08/09/2017
Creo que este tema ya está razonablemente bien cubierto en otros sitios de SE: Empezaría leyendo las primeras respuestas en este post y en este post , así como recursivamente leyendo cada recurso fuera de sitio vinculado + cada pregunta relacionada en la barra lateral .
ItamarG3 08/09/2017
@ Michael0x2a yikes. Bueno, es mejor que empiece.
2 Michel Billaud 08/09/2017
En FP, las funciones se pueden aplicar a otras funciones oa datos que contienen funciones, por lo que los mundos de datos y funciones no son muy separados (piense en una función sort (), con una función comparadora como parámetro).
2 aaaaaa 08/10/2017
Creo que también es importante tener en cuenta lo difícil que puede ser leer y comprender los beneficios de algo como la programación funcional. Para mí de todos modos, se tomó la programación imperativamente durante mucho tiempo para darse cuenta de la complejidad que el estado modificado trae. Una vez que me di cuenta de que era un problema real que tenía que resolver, la programación funcional era una solución natural y todo el material que explicaba qué programación funcional se comenzó a tener sentido.
1 Jeffrey Bosboom 08/11/2017
También recomiendo la respuesta excelente de Eric Lippert a ¿Por qué no se ha tomado la programación funcional todavía? de SO.

11 Answers


Ben I. 08/12/2017.

Hay respuestas hermosas a esta pregunta ya aquí, y no voy a tratar de reiterar cualquiera de los motivos que ya han sido cubiertos. Sin embargo, algo importante que no he visto aquí hasta ahora es que comparar POO a FP no es realmente terriblemente significativo. Es un poco como comparar el glass (el material) a las tables (los muebles). Cada uno de ellos tiene propiedades que pueden ser exploradas, pero incluso si las discusiones de estas propiedades pueden ayudarle a aprender sobre ellos, la comparación en sí no te dice mucho acerca de cualquiera. Las mesas de vidrio existen y tienen las propiedades de ambas. Del mismo modo, Scala, Clojure y Swift son lenguajes que son funcionales y OO.

Una comparación más significativa para la programación funcional es la programación imperativa. Los idiomas más populares en el mundo en este momento son todos imperativos 1 . Las lenguas imperativas se centran en valores y estados mutables, y se basan históricamente en Turing Machines . Los lenguajes funcionales son todo sobre las llamadas de función y las constantes inmutables, y se basan históricamente en $\lambda$-Calculus .

Los dos sistemas matemáticos se desarrollaron alrededor del mismo tiempo para resolver la misma pregunta: what is fundamentally computable? La Church-Turing Thesis , publicada antes de que existieran computadoras electrónicas, demostró que los dos sistemas eran igualmente poderosos, y además la hipótesis de que ambos podían calcular cualquier función computable, y que cualquier sufficiently complex system podría incorporar exactamente este mismo poder de computabilidad.

Una comparación más significativa para la programación orientada a objetos sería ... bueno, nothing . La filosofía orientada a objetos, que consiste en agrupar datos con funciones que rigen esos datos, puede aplicarse a cualquier paradigma de programación. La programación orientada a objetos tiene que ver con el scope and membership de funciones y datos. No importa si los datos son mutables, si el orden de las operaciones está definido, cómo se almacenan los datos, si las funciones son mutables ... si estamos creando instancias de datos que están agrupados con sus propias funciones, tenemos la núcleo de la programación orientada a objetos.

1 - Sólo si se descuentan de Excel, que es en realidad un lenguaje funcional de programación funcional, y es casi seguro que es utilizado por many more people que cualquier otro lenguaje de programación en la tierra.

3 comments
1 Daniel Jour 08/09/2017
+1, se podría comparar orientado a objetos orientados a datos, sin embargo.
3 Brilliand 08/09/2017
Lo opuesto de la OOP parece estar manteniendo una separación entre datos y comportamiento. (Sin embargo, estos opuestos no son mutuamente excluyentes - he visto programas que combinan imperativo and funcional and OOP and separación de datos y comportamiento - ellos simplemente hacen cosas diferentes en diferentes lugares.)
1 thesecretmaster♦ 08/12/2017
Los comentarios no son para discusión extendida; esta conversación se ha movido al chat .

Buffy 08/10/2017.

Aquí hablaré de Programación Funcional (FP) y Programación Orientada a Objetos (OOP) en una forma bastante pura. Los idiomas actuales, sin embargo, a menudo hacen concesiones para permitir las formas más antiguas, así como la programación de múltiples paradigmas.

Tanto FP como OOP se basan en la noción de programa "Estado", pero lo hacen de diferentes maneras. De hecho, hay realmente dos cosas diferentes que van por el término "estado" y es útil distinguir entre ellos. La versión de la mayoría de la gente se centran en cuando dicen "estado" es el conjunto actual de valores de las variables en un programa, ya sea en objetos o no. Esto depende de tener "variables" modificables en el programa.

Usando la notación de Pascal, x: = 2 da una variable entera un valor 2. Usted fija un estado. Más tarde, dentro del mismo ámbito, se le permite decir x: = 3 que "cambia el estado".

La forma en que la mayoría de la gente visualiza lo anterior es que la memoria de alguna máquina real o abstracta ha sido alterada de una manera específica. Me referiré a esta noción de "estado" como Explicit State . El estado explícito es la colección actual de valores de variables.

Sin embargo, hay una visión diferente e independiente de "estado" que la mayoría de los programadores son conscientes de, pero no siempre se centran en de la misma manera. En esta vista, el "estado de un cálculo" está representado por el contador de programa, que representa el foco actual de ejecución en un programa. Por ejemplo, ahora usando Java-como sintaxis:

if(x == 3){
    // a
    ....
} else {
    //b
    ....
} 

En algún momento de la ejecución, el contador de programas (PC) puede estar en el punto (a) o en el punto (b), pero no ambos simultáneamente, por supuesto. Si el PC está en el punto (a) entonces el "estado del cálculo" incluye el hecho de que x es 3. Si está en el punto (b) entonces el estado es que x no es 3. En esta vista el estado de la el cálculo cambia a medida que el programa se ejecuta (y es dinámico). En la primera vista el estado del programa se suele considerar como estático, aunque eso no es del todo correcto (ya que las cosas cambian). Me referiré a esta segunda noción de "Estado" como Implicit State . Es la ubicación actual de la PC y todo lo que implica sobre lo que ha pasado antes, no importa cómo se implementa.

Ahora a la pregunta: ¿cuál es la diferencia fundamental entre FP puro y POO puro?

  • Programación Funcional

Pure FP se basa en el estado implícito y desactiva (o elimina) el estado explícito. En Scheme, por ejemplo, un let da un valor a un identificador que es válido en todo un ámbito. Se called una variable en la documentación, pero es realmente un nombre dado a una constante. Una vez dado un valor, el nombre no hace referencia a ningún otro valor en ese ámbito, pero puede tener un valor diferente en un ámbito diferente (o mayor o menor).

Uno prevé un cálculo en un FP puro como una expresión que tiene un valor. Para calcular esa expresión se evalúan otras expresiones (recursivamente, por así decirlo) hasta que algunas expresiones se valoren a sí mismas (5, y "foo"). El estado del cálculo es puramente implícito, la ubicación del PC dentro de la cadena de recursividad. Cuando la cadena termina la expresión original puede producir un valor.

No hay "variables" en el sentido C o Pascal. Los valores nombrados (es decir, constantes) pueden asignarse a ubicaciones de memoria o almacenarse en la pila, o en la nube, o ... No se especifica necesariamente. En cierto sentido, el estado es una pila.

  • Programación orientada a objetos

La primera OOP fue en realidad Simula (1967), desarrollado en Escandinavia para hacer programación de simulación. Simula fue la principal inspiración para C ++. La primera OOP pure (y tal vez pure ) fue / es Smalltalk. Se convirtió en la inspiración para la mayoría de los OOPs modernos; Apple Pascal Objeto, Java, Python, .... Sin embargo, la mayoría de los otros idiomas OOP que Smalltalk comprometerse de varias maneras. Discutir pura OOP más profundamente requiere una excursión. Hay dos maneras de pensar en un objeto en una OOP; su creación y su uso.

  • Uso de objetos en OOP puro

En la OOP pura existe un objeto (de alguna manera) y se lo ve mejor como un "paquete de comportamiento". Responde a un conjunto de mensajes que son válidos para su tipo. Los mensajes pueden contener parámetros. Si tiene o no algo como "estado" es inmaterial. Se "comporta" cuando se envía un mensaje. Como parte de la realización de su tarea (definida por el mensaje y los parámetros) puede, por sí mismo, enviar mensajes a otros objetos. Algunos mensajes son de naturaleza funcional y devuelven valores (objetos o valores primitivos). Algunos no lo son. Necesita métodos no funcionales para, por ejemplo, impresoras de unidad y otros dispositivos externos.

En este punto de vista, no es fructífero pensar en los objetos como "estado" encapsulador. El estado no es material. Sólo el comportamiento importa. La implementación de un objeto might depender del estado guardado, o might confiar en delegar cosas a otros objetos a través de una cadena de mensajes (de nuevo, como la recursión a algún caso base).

Los objetos when used son paquetes de comportamiento, nada más.

  • Creación de objetos en OOP puro

Los lenguajes OOP, sin embargo, también proporcionan un mecanismo para la creación de objetos. Existen dos mecanismos principales para esto (Clases y Prototipos), que no afectan a la discusión aquí. Asumiré un lenguaje basado en clases ya que la mayoría de los programadores (no javascript) están más familiarizados con las clases. Al crear una definición de clase, el trabajo del programador es definir el comportamiento de sus objetos. En Java, eso significa que los métodos visibles (la visibilidad es un poco compleja para esta discusión, creo que no-privado para una simplificación).

Un objeto de la nueva clase debe ser capaz de responder a un mensaje dado (con parámetros, tal vez). Eso se puede hacer que suceda de diferentes maneras. Por ejemplo, el objeto puede diferir la acción a otro objeto. Pero también podría definir una variable (clásica), y darle un valor. Después de haber dado a esa variable un valor, es libre de recuperarla más tarde y (tal vez) modificarla. Pero no seas ingenuo sobre las cosas. El hecho de que el nombre de un método sea "setDisplay" no significa necesariamente que haya alguna variable (en cualquier lugar) que cambie su valor. Es un concepto, nada más. El objeto de somehow (hasta el programador) conservará el valor dado para que el "estado de la computación" pueda avanzar.

Por lo tanto, en esta vista OOP "pura", el trabajo de creación de objetos es el trabajo de definir los comportamientos a los que el objeto puede responder. Usted puede pensar en un objeto (si lo desea) como un paquete de estado + comportamiento, pero que sólo debe trabajar en la fase de definición, no la etapa de uso.

Tenga en cuenta que en esta vista, un cálculo se ve como una colección de objetos independientes que se comunican a través del paso de mensajes. Los objetos pueden ser normalmente activos (modelo de actor) o no, siendo estos últimos más comunes. Un objeto es, en el caso de no actor, sólo activo cuando se ha enviado un mensaje. Es fácil visualizar que un PC viene junto con cualquier mensaje que permite al objeto ejecutar el método. Si el objeto envía un mensaje en sí, el PC se pasa a lo largo, así, dejando que el receptor del mensaje actúe.

  • Por qué esta vista OOP es importante.

Uno de los problemas de aprender a programar es el problema de cuánta información debe tenerse en cuenta a medida que avanza. Si fuera necesario retener todos los detalles del programa, sería una tarea imposible. Por lo tanto, utilizamos varias instalaciones de abstracción (instalaciones mentales) para reducir la tarea. No puedo recordar el estado de 4gb de valores. No puedo ni siquiera recordar el estado implícito de una declaración if si anidado más de unos 4 niveles de profundidad. Por lo tanto, no escribo estos programas y en su lugar, crear objetos simples con comportamientos sencillos. También creo objetos que tienen cualquier estado explícito privado - sin excepciones. Diseño objetos para que can efectivamente pensar en ellos como nothing but paquetes de comportamiento, aunque Java sin duda tiene instalaciones que me permiten hacer lo contrario. Sin embargo, si rompo mis reglas, mi programa se hace más difícil de entender, usar y modificar.

  • Un programa OOP puro es un conjunto de objetos simples con métodos simples. La complejidad del programa está en las interacciones de objetos, no implementaciones de los objetos.

Sí, escribo muchas clases. Pero cada uno es simple de conceptualizar y simple de construir. Cada objeto es un paquete de comportamiento, nada más.

5 comments
no comprende 08/09/2017
La descripción funcional de la vista del estado del programa me recuerda al sueño de Bohm acerca de cómo el universo podría ser modelado como una cosa inmensa, intemporal e inmutable con un único fotón que va y viene a través del tiempo (es su propia antipartícula) creando todo lo que existe, y lo "vemos" solo a través de nuestra proyección de proyección de película. Su descripción de OOP refleja su preferencia por funcional, y creo que es un poco diferente de la mayoría de la gente, como su vista de PC es diferente de la vista habitual de estado. Gracias por explicar de tal manera que finalmente te entiendo!
2 Buffy 08/09/2017
En realidad, don't tengo una preferencia por FP. De hecho, el único lenguaje funcional en el que alguna vez fui bueno fue ML. Dependo de la sintaxis concreta para ayudar a organizar mis pensamientos. Mi opinión es verdaderamente OOP, sólo una versión más profunda y más pura que la mayoría de la gente tiene y pocos idiomas OOP requieren. El único software realmente serio que he construido (bastante) ha sido en los lenguajes OO. Pero mi experiencia se remonta a un largo camino y he tratado de desarrollar un estilo que es sostenible. Mi opinión no es única, por supuesto. Me alegro de haber sido útil.
1 no comprende 08/09/2017
Tratando de imaginar un software realmente serio ... (En cualquier caso, quería decir que su view es "funcional" en lugar de qué language prefiere, ahora que creo que realmente entiendo la visión funcional (si realmente entiendo algo). imprimí tu Respuesta y la entregué a mis estudiantes (espero que no te importe) porque es la mejor explicación que he visto de la vista de estado de PC. Dibujó un diagrama de cuadros en el tablero, representando variables, luego un bosquejo de líneas de código indentadas, representando su opinión del estado, entonces agitó mis brazos mucho e intentó explicar porqué lo encontré tan emocionante.
1 Buffy 08/09/2017
Bueno, mi software "serio" también es divertido. Debería ser divertido. En la referencia anterior, sin embargo, serio también significó más de 15.000 despliegues.
2 Paŭlo Ebermann 08/10/2017
Los lenguajes funcionales a menudo usan el término "variable" como la matemática - un nombre para algún valor que es constante durante su vida, pero el mismo nombre puede referirse a un valor diferente la próxima vez que se ejecute el algoritmo. Una constante verdadera tiene el mismo valor cada vez.

TwoThe 08/09/2017.

FP y OOP son herramientas en la caja, ninguna de ellas es mejor o peor. De la misma manera que usted no le preguntaría si usar un martillo o un destornillador para poner en un clavo, no debe preguntar si utilizar FP o OOP.

La pregunta debe ser: ¿cuál es la mejor manera de resolver su problema a mano?

OOP supera cuando se necesita describir objetos abstractos con código (de ahí el nombre). Describir las habilidades y características de un automóvil es algo FP no está hecho para, por lo que elegir FP para esta situación sería dolorosamente complicado.

Viceversa FP sobresale cuando los algoritmos pueden ser escritos como funciones matemáticas en la mentalidad de f(x) -> y (funciones más complejas son también muy posible). Usando OOP para describir el resultado de square(x) es posible, pero sin sentido complicado.

En la programación moderna FP normalmente se utiliza cuando los volúmenes de datos necesitan ser transformados. Si necesita mapear de Z a Y usando la función de transformación f, entonces puede simplemente escribir eso en código usando FP, iE en Java como esto:

// equivalent of Yn = f(Zn)
List myYs = myZs.stream()      // for each z in Z
  .map(MyClass::f)                // transform y = f(z)
  .collect(Collectors.toList());  // and store y in a list 

Hacer lo mismo en OOP sería algo como esto:

class Z {
  private int myValue;

  public int getValue() {
    return this.myValue;
  }
}

class Y extends Z {
  static Y convertFromZ(final Z z) {
    // ...
  }

  @Override
  public int getValue() {
    return convertFromZ(super.getValue());
  }
}

List myYs = (List) myZs;  // <-- really dirty hack 

Esto hace que sea obvio por qué no existe un gráfico de comparación: porque esos dos conceptos son completamente diferentes.

2 comments
1 ItamarG3 08/09/2017
¡Bienvenido a Educadores de Informática ! que es una muy útil descripción y explicación. ¡Gracias!
jcast 08/09/2017
Me gustaría preguntar si usar un clavo o un tornillo, por ejemplo: popularmechanics.com/home/tools/how-to/a18606 / .... OO vs FP es diferente en que es posible (razonable) hacer ambas cosas, por ejemplo, hacer x.square() devolver un nuevo objeto o escribir un método expr.calculated_type() en un compilador.

David 08/09/2017.

Ya hay varias buenas respuestas, pero me gustaría añadir lo siguiente.

El código funcional es (al menos en teoría) más fácilmente paralelizado. Esto es importante porque hemos alcanzado el límite de lo rápido que podemos ejecutar circuitos integrados. (Sé que es una simplificación excesiva, estoy tratando de mantenerlo sencillo para la audiencia del OP.)
Por lo tanto, aunque no puede hacer que los núcleos individuales en su CPU funcionen mucho más rápido, can agregar núcleos a la CPU.

Ahora pensemos en un solo programa grande. Múltiples núcleos solo acelerarán tal programa si puede ser dividido en "trozos" independientes que se pueden dividir en núcleos individuales. Y seamos claros sobre lo que significa "independiente": ningún fragmento debe tener efectos secundarios que puedan afectar a cualquier otro trozo (y probablemente los trozos no dependan de la salida de otros trozos).

Este es un área donde la programación funcional sobresale. Por el contrario, tratar de garantizar la coherencia de objetos a través de múltiples subprocesos o procesos puede ser una pesadilla. Cuál es una razón allí es una gran cantidad de interés actual en FP.

Lo malo es ... como señala Jared, en un juego, en el paradigma FP, probablemente mantendrá la apatridia al tener la rutina de "ataque" devolver una copia completamente nueva del orco (o cualquier enemigo) bajo ataque. Pero:

  1. Reconstruir todo el orco es probablemente una operación no trivial - es casi seguro que va a ser más costoso que ajustar los puntos de golpe del orc (cambiar el estado de un objeto existente).
  2. Y ese es un caso bastante simple. Es probable que los cambios en el estado del objeto causen otros cambios - por ejemplo, el orco podría obtener un bono de ataque si sus puntos de éxito caen por debajo de cierto nivel. En FP, esto probablemente resultaría en la construcción y la devolución de otro objeto orc. Y así.
  3. La construcción de nuevos objetos enemigos y / o jugadores va a aumentar la sobrecarga de la gestión de memoria. Todos esos objetos desechados probablemente van a necesitar ser recolectados de basura; y con toda esa construcción / destrucción, que probablemente va a obtener la fragmentación en el almacén de memoria o montón.

En general, la composición es una buena cosa.
Pero una cosa es hablar de f(g(h(x))) cuando f , g devuelven valores numéricos. Cuando cada una de esas funciones en la cadena de composición puede devolver un objeto grande y / o complejo ... esto puede resultar en un rendimiento inaceptable, incluso para un juego para un solo jugador.

Ahora piense en una aplicación financiera, en la que la reconstrucción de un cliente puede implicar volver a leer el historial de transacciones de varios meses (o años).


Como han dicho otras respuestas, FP es muy bueno en problemas matemáticos. Si necesita administrar el estado mutable, la OOP imperativa podría ser una mejor opción. Esperemos que esto haga la diferencia un poco más concreta.

3 comments
1 ItamarG3 08/09/2017
¡Bienvenido a Educadores de Informática ! Una respuesta muy profunda, abordando muchos puntos. Gracias.
2 Matthieu M. 08/10/2017
Existe este "Mito del Compilador Suficientemente Inteligente". En teoría, un compilador podría insertar g y h en f , realizar un análisis de escape para darse cuenta de que la referencia no puede haber escapado, y por lo tanto modificar el valor en el lugar ya que ningún observador puede realizar la modificación. Por supuesto, un lenguaje sin GC haría esto mucho más fácil (eliding escapar análisis en parte).
no comprende 08/10/2017
Sería interesante extender el análisis a algo really masivamente paralelo, como la percepción visual en el cerebro. ¿Cómo puede una miríada de procesadores analógicos de un bit funcionando a 100 Hertz lograr algo? Bueno, ¿cómo un millón de monos sentados en los teclados llegan a la sala de Carnegie? Practice!

Robert Fisher 08/09/2017.

No esperaría encontrar una tabla de comparación porque OOP y FP no son conceptos que se excluyan mutuamente.

OOP es sobre encapsular datos en objetos detrás de interfaces y usar herencia para construir objetos en piezas reutilizables.

FP, sin embargo, trata de no cambiar estados o tener efectos secundarios.

Puede tener un programa OOP con objetos inmutables. (Puede clone un objeto, pero no puede cambiar el estado de un objeto existente). Puede tener un programa OOP donde los métodos no tengan efectos secundarios.

Puede tener un programa FP que encapsula sus datos en objetos detrás de interfaces y utiliza la herencia.


no comprende 08/09/2017.

No he encontrado una tabla de comparación grande como usted está buscando. Mi breve respuesta sería:

  1. Utilice Functional para las cosas que son math-y o language-y. Utilícelo cuando esté investigando la computabilidad u otros aspectos o proyectos más académicos.
  2. Utilice Procedural cuando desee que las personas menos experimentadas (como los estudiantes) sean capaces de comprender su código de manera sensata.
  3. Utilice OOP para proyectos grandes que requieren almacenar datos y cambiarlos durante las interacciones con los usuarios.

Más que esto, no puedo decir.

5 comments
ItamarG3 08/09/2017
Oh. Es una buena manera de decirlo.
1 kuroi neko 08/09/2017
Eso sería sentido común. Ahora el problema es que no siempre tienes la opción. Intente programar en C ++ a partir de C ++ 11 adelante y usted tendrá que envolver su cabeza alrededor de la plantilla metaprogramming incluso para mover un matchstick. La programación funcional es una moda que invade todo tipo de campos de la ingeniería de la computación.
no comprende 08/09/2017
@kuroineko Cuando vi por primera vez las plantillas en C o C ++ hace unos 20 años, "Volví la cola con valentía y corrí". No he intentado usarlos porque no he tenido que hacerlo. (Si yo tuviera). Pero, al ir más allá de los contrafácticos y las conjugaciones del verbo Ser (que muchos lenguajes no tienen, por cierto) he estado aprendiendo y enseñando C # últimamente, y parece muy bien diseñado. Aprendí Lisp y APL hace 30 años en la universidad (antes de aprender C) y no he sentido un impulso convincente de volver a aprenderlos por algo que he tenido que hacer desde entonces. (Suficiente con los tiempos ya!)
Pharap 08/11/2017
@ kuroineko Usted no necesita saber nada sobre la plantilla de metaprogramación para beneficiarse de C + + 11. Lo más que un usuario tiene que preocuparse con las plantillas es saber cómo escribir std::vector y tal vez un poco sobre cómo funcionan (es decir, plantilla de instatiation) y cuando se pueden inferir los parámetros de la plantilla. Si hubieras dicho expresiones lambda en vez, estaría tentado a subir, pero las plantillas son generalmente completamente evitables. De hecho, C ++ 11 lo hizo más evitable: antes de C ++ 11 necesitaría una meta-programación de plantillas para calcular factorial en tiempo de compilación, ahora solo puede usar una función constexpr .
1 no comprende 08/12/2017
No recuerdo mencionar plantillas en mi Respuesta ...

Cycomachead 08/09/2017.

Esta es una pregunta muy amplia, por lo que voy a señalar a un par de lugares y luego dar una explicación muy corta.


Creo que es importante tener la mentalidad correcta acerca de los paradigmas: Al final del día, son una herramienta para ayudarle a organizar un proceso de pensamiento alrededor del código. Todos ellos le permiten realizar las mismas tareas.

En general, casi todos los lenguajes o ambientes de hoy son "multi-paradigmas". Incluso Java (que es famoso como OOP porque todo está obligado a estar en una clase) está escrito en un estilo que combina paradigmas imperativos y procedimentales con OOP. Más recientemente, Java incluye más y más elementos que están en el estilo funcional.

Cuando se trata de funcional vs OOP, hay una cosa grande que viene a la mente.

Ser "apátrida" o tener "estado"

Estado significa que tiene algunas propiedades o información almacenada, como el nombre de un sprite o una pantalla en la que se genera información. En un mundo funcional, especialmente uno que intenta ser "puro", en su mayoría va a tratar de componer (o encadenar) funciones juntas. El objetivo es tener una función, por ejemplo, compute_something(an_object) que sólo necesita la información pasada a ella (argumentos) y nada más - es decir, no tiene "estado". A continuación, devolverá un nuevo valor, y no modificar o mutar su entrada. En el mundo OOP, es común pensar en un objeto que tiene estado, es información sobre sí mismo y cómo interactúa con el mundo. Podrías hacer algo como object.compute_something() , donde compute_something es una propiedad (una función) vinculada a ese objeto, y llamándola, modificas alguna propiedad de ese objeto.

Un ejemplo común de esto es ordenar una lista. En un paradigma funcional, probablemente harías sorted_list = sort(some_list) . Mientras que en un paradigma OOP, probablemente haría some_list.sort() y la próxima vez que use some_list se ordenará.

Formar esto a veces hay otras diferencias, como la diferencia que las lenguas tratan los "tipos" de datos, pero las cosas pueden volverse turbias rápidamente.


Para responder a su pregunta original sobre los proyectos: Es realmente difícil de decir. Podría conceptualizar una aplicación de conversión de unidad como tener un montón de objetos (como uno para cada tipo de sistema de medición), o ya que es "mathy-", también se puede conceptualizar fácilmente como una función simple con una tabla de búsqueda para varias tasas de conversión. En realidad, el paradigma dependerá del entorno con el que esté trabajando, tanto como dependerá de la estructura teórica del código.

2 comments
ItamarG3 08/09/2017
Interesante. No había pensado en algunas de las cosas que usted señaló. Gracias
Gilles 08/11/2017
"Mientras que en un paradigma OOP, probablemente haría some_list.sort () y la próxima vez que use some_list se ordenará." No. Con un paradigma imperative , haría sort(some_list) ( some_list.sort() ) o some_list.sort() (OO) para cambiar some_list . OO vs procedural es ortogonal a imperativo vs funcional. En OOP funcional, se haría let sorted_list = some_list.sort() .

Jared Smith 08/10/2017.

Es difícil poner esto en una forma que los estudiantes de pregrado inexpertos apreciarán, pero bien ...

"Normalmente es el caso de las tecnologías que se puede obtener la mejor visión sobre cómo funcionan viéndolos fallar" - Neal Stephenson, In the Beginning was the Command Line

Dado que OOP es el gorila de 500 libras del mundo de la programación y FP la ascendencia relativa esta comparación podría ser un poco sesgada por falta de puntos de datos. Sin embargo, dos importantes casos de fracaso vienen a la mente.

1. Intercambio de Datos

El Dios del Sol Microsystems otorgó a los Caballeros Paladinos de la Programación sus Mandamientos grabados en tabletas de silicio más puro para la posteridad y de donde Sus discípulos fundaron la Iglesia de Java. Aquellos que eran tan estúpidos como para afirmar que estos mandamientos desde lo alto eran un Pacto con los Demonios del Desempeño y Sintaxis Popular bastardizando la pureza prístina de Smalltalk fueron denunciados como herejes. Y los proselitistas extendieron su fe hasta los rincones más remotos del reino.

Así que sí, la gente comenzó a usar OOP para todo. Pero había (al menos) una arena donde esto falló por completo: IPC. Intercambiar datos a través del límite de threads / machines / networks / languages ​​fue un problema. Exactamente cuánto de un problema se puede inferir de enumerar algunos de los (muchos) intentos de resolverlo de una manera OO que desechos de la historia de la historia: CORBA, RMI, WSDL, DCOM ... y también de la extrema proliferación de la utilización generalmente en forma de XML (en contraposición a usar XML-RPC).

Así que ahora la gente todavía lo hace, pero generalmente usamos mecanismos de transporte que son stateless (como HTTP) y sobre ellos enviamos datos agnósticos del lenguaje (sexprs, XML, JSON). Así que en la estructuración de los systems intercomunicación FP ganado porque el trato con el estado es bastante difícil por sí solo, pero se convierte en un orden de magnitud más difícil cuando se agrega hilos, entonces otro orden de magnitud (o dos) más difícil cuando se agrega intercomunicaciones y otro orden de (o más!) más difícil aún cuando usted tiene muchos-a-muchas comunicaciones con las necesidades de la eventual coherencia o el orden cronológico preciso de los eventos. De hecho, sólo pensar en ello lo suficiente como para escribir ese último bit aumentó mi presión arterial a niveles peligrosos.

Lo que no quiere decir que la gente no use OOP en ese espacio en absoluto, pero no es muy común y la búsqueda para encontrar el Protocolo de la Gran OOP-que-Hace-EZ es una búsqueda más fácil en comparación con fusión fría o la Ciudad Perdida de El Dorado (sin financiamiento de VC para usted!) que tratar de crear la próxima aplicación de red social megahit (\ $ \ $ purr \ $ \ $).

2. Programación de Juegos.

Juegos de programación en FP es ciertamente posible , pero no necesariamente recomendado. Y esto va más allá de la falta de bibliotecas y middleware o la necesidad de exprimir tanto fuera del hardware como sea posible: cuando mi nivel 6 Half-Elf Berserker golpea un orco con su martillo de Doom espero que orc sea el mismo orc menos 3D6 hp no es un orco nuevo con un valor de hp diferente que el anterior. El problema es que los juegos se relacionan generalmente con dos entidades diferentes: las things y las rules sobre la interacción de esas cosas a as they change over time . Nadie quiere ir a todos los Juegos de Guerra y ver a un supercomputador jugar a sí mismo en el tic-tac-dedo del pie hasta que se entera de la futilidad de la guerra nuclear. OOP chupa en las reglas de modelado (que FP sobresale en), pero OOP es great para modelar cómo las cosas reificadas change over time .

De todos modos, como dije al principio no estoy exactamente seguro de cómo iba a hacer todo esto accesible a CS undergrads (basado en mi memoria de lo que yo y mis compañeros eran como cuando yo era uno). Pero creo que mirar dos fracasos de alto perfil es un buen lugar para empezar.

En pocas palabras, como las otras respuestas han dicho que son modelos mentales muy diferentes. Cada vez que intente utilizar uno que no se asigna fácilmente al dominio del problema, tendrá problemas. Así que ilustrando algunos de esos dominios con la forma en que uno o el otro es un ajuste más natural (y mis ejemplos anteriores de meter clavijas cuadradas en agujeros redondos) y por qué podría ser la mejor manera de abordar el tema.

5 comments
3 Ben I.♦ 08/09/2017
Su historia es hacia atrás. La programación orientada a objetos es el novato aquí. FP precede al lenguaje proto-OO más temprano en una década. LISP, un lenguaje funcional basado en el Lambda Calculus de la Iglesia, fue el segundo lenguaje de programación de alto nivel jamás creado. Salió sólo 2-3 meses después de FORTRAN (el lenguaje de programación de alto nivel más antiguo que existe).
3 Jared Smith 08/09/2017
@BenI. Soy consciente de la cronología. Pero en términos de mindshare en la vida de los estudiantes de pregrado (últimos ~ 20yrs) OOP ha sido absolutamente dominante. Como la programación y la informática están creciendo rápidamente, un subconjunto decente (la mayoría?) De las personas en el arte llegó a la mayoría de edad en la era Javásica y están siendo expuestos a lo que LISP y Erlang (y ML y Haskell) han estado haciendo durante décadas .
ComicSansMS 08/10/2017
En cuanto a su argumento de programación de juegos: John Carmack enseñó a su hijo la programación de juegos en Racket , un dialecto LISP.
1 no comprende 08/10/2017
¡Otro lanzador de metáforas coloridas! También sobre el tiempo.
1 Jared Smith 08/10/2017
@ nocomprende las metáforas inexactas son siempre más pegajosas que el discurso técnico exacto pero seco: D

Peter 08/09/2017.

As I read your post, I see your question as simply this:

where might I find a thorough comparison between the two [OOP and FP], which can explain which should be used for some kinds of tasks\projects?

The best explanation I have seen is in the context of the Programming Languages MOOCs offered through Coursera modeled after this course at UW .

The class works through, in order, a statically-typed functional language (ML), a dynamically-typed functional language (Racket), and a dynamically-typed object-oriented language (Ruby). Since this is an upper-division course and students presumably are somewhat familiar with it, Java is thrown in for comparisons when relevant as a statically-typed objected-oriented language.

If you want to find a thorough comparison, build projects with each approach, spending time to learn the relevant nuances of FP and OOP along the way. There is no chart or tutorial that can substitute for this work; it simply takes time and practice. Based on my experience, the work of this course will not disappoint. There are short mini-lecture videos, excellent reading notes, and challenging homework assignments all available for free.

At the end of the course, the professor does an excellent job breaking down OOP v. functional decomposition. By the time you reach the end, you will have a clear picture as to how these approaches differ, where their relative strengths and weaknesses like, and when/how to apply each paradigm to a particular problem.

5 comments
1 Ben I.♦ 08/09/2017
I disagree with you that you will learn about "how these approaches differ" - they don't differ in any meaningful way. They are orthogonal concepts from the start. It's like saying that you will learn how tennis differs from clay (of which the court is made), or how paintings differ from paper .
Peter♦ 08/09/2017
@BenI. I'm not enough of a programming languages expert to speak with my own authority on such a matter, but I have a feeling the professor sees things differently. The end of the course dives in to how each approach takes fundamentally opposite approaches to program decomposition. From the lecture notes: "We show that the two approaches [OOP and FP] largely lay out the same ideas in exactly opposite ways." courses.cs.washington.edu/courses/cse341/17sp/unit8notes.pdf
Ben I.♦ 08/09/2017
In that case, my disagreement is with the professor. Perhaps he overstated his case? The sentence that you have quoted would seem to be disproven by the existence of the many functional, object-oriented languages.
no comprende 08/09/2017
@BenI. Godel's Theorem says that every sufficiently powerful representational method (Formal System) must be either incomplete or inconsistent (or both). So, it makes perfect sense to me that a language can include both Functional and Object Oriented capabilities, which are "exactly opposite". The course seems to be about different approaches , not different languages or even varying language features. No true language would not give you enough rope to hang yourself with, right? Thanks for the bit about Church-Turing thesis though. I must have slept through that sermon. Er, lecture.
Ben I.♦ 08/09/2017
@nocomprende Your statement is beautiful, but I suspect it is ultimately more poetic than it is meaningful. Godel is talking about the limits of provability , which is simply unrelated to the notion of whether various engineering philosophies can play nicely with one another.

Pharap 08/13/2017.

Truth be told you will never truly understand the difference until you actually learn and use both a functional and an object oriented language. I say that as someone who has learnt both object-oriented languages (C#, C++, Java) and functional languages (Haskell). I will however attempt to explain the crux of it.

My answer will be looking mostly at functional programming from an object-oriented point of view, as the features of object oriented programming are already very heavily documented due to its popularity whereas the features of functional programming are much more scarcely documented.


Firstly imagine a computer language as a tool (or a collection of tools). Every tool in the world has a particular purpose or a set of tasks that it's good for, and the same is true of languages.

Functional languages tend to work better for problems that involve data-processing and deterministic processes. As such they are liked by scientists and mathematicians who can think in terms of pure data and algorithms.

Object oriented languages are better for modelling complex interacting systems. They are preferred by businesses because of their ability to mediate complex tasks and by game developers because of their usefulness in modelling the world.

They can of course be used for other things, but these are typically what the approaches are centred around.


At the language level the crux of the matter that sets functional languages apart are these factors:

  • They shun local state (with caveats).
  • By extension they forbid functions from having side-effects (functional 'purity').
  • Implicit type inference
  • The dependence on 'lists'
  • The use of sum types
  • The use of type classes (or 'contracts')
  • Implicit currying

(Note that these are not all completely necessary for something to be considered a functional language, but they are features that are commonly associated with functional languages because they can be found in a wide variety of functional languages, particularly the most popular ones.)

State:

In a functional language, values are created and they do not change - instead the old value is destroyed and a new value is created. At face value this seems a bit crazy, but in reality this abolition of state (with caveats) is only at the language-level, the compiler translates the source code into machine code that still has a concept of state, which somewhat breaks the illusion and makes this notion a bit less shocking.

The caveats I mentioned are that there are ways to emulate state in one way or another. One way of doing this is by maintaining the state as a function variable and another way is by using a construct called the 'State monad'.

Purity:

Equally, although all functions must be 'pure' (ie must not have side effects), there are various monads that allow there to still be side effects without breaking the laws of the language. Monads are how any kind of IO (file IO or terminal IO) is made possible. Essentially, the behaviour of the program is bound to the monad through functions that act aa means of sequencing - the monad then represents a list of actions that describe the translation and processing of the data.

Type inference:

(This is not found in all functional languages and may sometimes be found in certain object-oriented languages such as C# and C++.)

It is where the compiler is able to evaluate the type of an expression by looking at the types of the values and functions in the expression and deducing what the valid results could be. If there is only one unambiguous match, the compiler is able to infer the type, making many definitions as simple as the values and functions themselves - no explicit typing involved. In other cases, there is ambiguity and some type notation must be used to disabiguate the result.

Lists:

Furthermore, the core data type of functional languages is a kind of singly-linked list often referred to simply as a 'list'. This takes the role of the basic collection datatype and is used how arrays and dynamic arrays are used in many object-oriented languages.

Another significant difference is the language-level support for sum types. Sum types are like objects with different constructors, and work sort of like inheritance in object oriented languages. That is, the type itself can be an abstract concept (eg a tree) and the constructors for it can represent different values of that concept (eg and empty tree, a leaf node and a branch node). It is because of this that tree data types are very easily represented in functional languages, and as such they are well-liked for solving mathematical tree-related problems and for implementing parsers and/or compilers.

Type Classes (or 'contracts'):

Type classes are similar to interfaces in object-oriented programming but have the distinction that they are not implemented at the time the datatype they are applied to is defined, they are implemented after the type has been defined. This means that they can be applied after the fact to datatypes that one does not 'own'.

Type classes are defined simply as a 'contract' that list a series of functions and/or values for which the obeying datatype must have an implementation. In effect the 'contract' states "any datatype said to implement this type class must provide an implementation for these functions".

For example there could be a datatype addable a (Where a is a type variable - a symbol standing in for an as yet undeclared type) that specifies a function called add with the signature 'a -> a -> a' (a function accepting two arguments of the type represented by a and returing a value of the type represented by a ). This loose definition means the addable type class can be implemented by many different data types, including Int , Float and any user-defined arithmetic type.

Currying:

(Note that not all functional languages support this, but it is much more commonly found in functional languages than in object oriented ones.)

Currying is a technique named after Haskell Curry (the same person for whom the language Haskell is named). Currying means that a function is only bound to one argument and then returns either a result or another function accepting an argument. In functional languages, all functions are implicitly curried, which means that no function actually accepts more than one argument. This in turn means that when you write a statement like add 3 5 , what actually happens is that the 3 gets bound to the add function, which then returns a function accepting a number, to which the 5 gets bound, and only then does that return a result.

This probably seems insane to someone not used to the idea, but it actually makes a lot of things much easier. For example there is typically a function called map which takes a function and applies that function over the contents of a list (much like a loop could do in imperative languages), and the ability to curry functions makes the definition of a the function passed to map very simple. If, for example, you wanted to add 5 to a list in Haskell, you could simply write map (+5) list - the (+5) takes the function + , binds it to the value 5 and returns a function taking a number and returning the result of that number + 5 .

5 comments
3 Matthieu M. 08/10/2017
I am afraid this answer conflates Functional Programming and Haskell. At the very least Type Inference, Type Classes and Currying are NOT a hallmark of FP.
1 Matthieu M. 08/10/2017
Lisp is dynamically typed, so no type inference is necessary (or meaningful). Possibilities for making it statically typed are discussed here .
1 Pharap 08/10/2017
@nocomprende I am aware of that saying and its application to computer languages. It's often applied to patterns too. (The bit I got hung up on was the word 'tale', which as far as I know is a synonym for 'story', which doesn't really fit the sentence.) Technically humans are animals. At any rate, this seems like an esoteric, slightly poetic tangent rather than a comment about the answer.
1 no comprende 08/10/2017
A tangent is the only way you can avoid going round and round. The entire question is about differences between languages (or at least approaches using languages). I was just putting in a warning that we often need to take a step back from debates and consider carefully the basis for the whole question. I suppose it was not so much directed at your answer specifically. I will delete my comments if you wish :)
2 Gilles 08/11/2017
Currying is inherently possible in any functional language, but whether it's used has little relation with the design of the language. For example Standard ML and Ocaml have a very similar core, but SML favors tuples as function arguments while Ocaml favors currying. (“Favors” means that this is what the standard library uses and the compiler optimizes this case better.)

kuroi neko 08/09/2017.

Functional programming is all the rage nowadays. It relies on the illusion that stateless objects and immutable data structures will keep the bugs out. Which is of course nothing but a self-fulfilled prophecy.

Statelessness and immutability are the current Holy Grail and Golden Fleece, mostly because they allows to write junk code faster (a function will always return the same result regardless of the current state of the system, so once it's debugged we're pretty much safe, right?) and we don't know any better way of using these new shining CPUs (functional programming requires a lot more resources than plain old procedural / object oriented approaches - just look at the exponential growth of C++ compile time!).

Functional programming is easier and faster to write. It encourages to concentrate on generic and simple building blocks and follow a bottom-up path.
On the other hand, it tends to become verbose and unmaintenable fast, what with the layers upon layers of progressively complexified functions you have to write.

With OOP you need at least some top-down approach. A general sketch of your final architecture before you can even start coding. After a couple decades of "extreme" and "agile" programming, the dreams of an easy way out of this initial planning are slowly starting to recede (after having cost an unknown but probably sizeable fraction of the world's GDP in failed projects and botched software). Now, with the shiny GAFAs as role models, functional programming is taking over as the new magical paradigm.

5 comments
2 no comprende 08/09/2017
This was probably downvoted for tone and being mostly opinion, but I sympathize with the overall pessimism towards the hyped and constantly changing 'paradigms' of a new and not very unified field. It reminds me of the struggles of Psychology, which is still discovering what might be fundamentals. I just wish we would at least present (teach) those fundamentals of CS that we have had for decades! Lots of varied opinions on that, even in this tiny backwater.
2 Jared Smith 08/09/2017
This is full of unsubstantiated opinions and reads more like a rant than an answer. Hype is orthogonal to utility: things can be anywhere in the matrix of sexy/boring and useful/superfluous.
1 kuroi neko 08/09/2017
@Pharap indeed, that's what I call whims of fashion. Templates in C++, stateless and immutable structures all over the web, JavaScript and Python being used as poor man's FP... Immutability and statelessness can be very appealing when dealing with concurrent processes (multithreading that has become mandatory since we started hitting the speed limit of a single CPU, or networking, after 30 years of calamitous efforts to synchronize data brokers), but still they are no silver bullets: costly, hard to read, relying on increasingly complex (and unreliable) tools to reach OOP performances.
1 Pharap 08/10/2017
@kuroineko I wouldn't knock templates because they can be incredibly useful and time-saving in the right hands (emphasis important), the ability to write them is certainly more useful for library writers than regular programmers though. I can understand the want for statelesness (it's more about the web's core principle of robustness), but I agree with JavaScript and Python creeping into territory they are unfamiliar with (functionalism).
1 Pharap 08/10/2017
@JAB They can do if the problem they are solving is well suited to generics (such as writing datastructures or arithmetic types), but those cases occur less frequently than the standard case for most programmers. Plus there's the same danger with templates as there is with programming patterns, and that's the "this is cool, let's make everything a template" mentality. The danger doesn't come from the templates themselves, it comes from them being considered a cool thing to know - it attracts people who will learn how to use them but not when to use them.

Related questions

Hot questions

Language

Popular Tags