Quel est le prochain niveau d'abstraction? [fermé]


15

Étant donné que les langages de programmation n'utilisaient initialement que des lignes de code exécutées séquentiellement, il a évolué pour inclure des fonctions qui étaient l'un des premiers niveaux d'abstraction, puis des classes et des objets ont été créés pour l'abstraire encore plus; quel est le prochain niveau d'abstraction?

Quoi de plus abstrait que les cours ou y en a-t-il encore?


17
Vous semblez penser que c'est une progression linéaire, avec un ordre ("X est plus abstrait que Y est plus abstrait que Z"). Je ne suis pas d'accord.

2
Ce serait une assez bonne idée de dire pourquoi vous priez de différer. ;) (lire: ça m'intéresse!)
sergserg

3
Je propose l'ultime "abstraction": faites ce que je pense, pas ce que je tape. ;)
Izkata

1
@Delnan: L'abstraction n'introduit pas un ordre total, mais il est possible de dire "plus abstrait", "moins abstrait". Par exemple, une implémentation générique de tri par fusion est plus abstraite qu'une implémentation de tri par fusion qui ne fonctionne que pour les entiers.
Giorgio

2
Bros, apprenez-vous une théorie des catégories. Ensuite, nous pouvons discuter de ce que l'abstraction signifie vraiment comme des hommes civilisés.
davidk01

Réponses:


32

Je pense que vous avez des idées fausses sur l'histoire de l'informatique.

La première abstraction (en 1936) était, en fait, le Lambda Calcul d'Alonzo Church, qui est le fondement du concept de fonctions de haut niveau et de tous les langages fonctionnels qui ont suivi. Il a directement inspiré Lisp (le deuxième plus ancien langage de programmation de haut niveau, créé en 1959), qui à son tour a tout inspiré de ML à Haskell et Clojure.

La deuxième abstraction était la programmation procédurale. Il est issu des architectures informatiques de von Neumann où des programmes séquentiels ont été écrits, une instruction à la fois. FORTRAN (le plus ancien langage de programmation de haut niveau, 1958) a été le premier langage de haut niveau à sortir du paradigme procédural.

La troisième abstraction était probablement une programmation déclarative, illustrée pour la première fois par Absys (1967), puis par la suite Prolog (1972). C'est le fondement de la programmation logique, où les expressions sont évaluées en faisant correspondre une série de déclarations ou de règles, plutôt qu'en exécutant une série d'instructions.

La quatrième abstraction était alors la programmation orientée objet, qui a fait sa première apparition dans les programmes Lisp dans les années 60, mais a ensuite été illustrée par Smalltalk en 1972. (Bien qu'il semble y avoir un débat quant à savoir si le style de transmission de messages de Smalltalk est l'abstraction orientée objet One True. Je ne vais pas y toucher.)

Toutes les autres abstractions, en particulier sur l'architecture informatique traditionnelle de von Neumann, sont des variations sur ces quatre thèmes. Je ne suis pas convaincu qu'il existe une autre abstraction au-delà de ces quatre qui n'est pas simplement une variation ou une combinaison d'entre elles.

Mais une abstraction n'est, en substance, qu'un moyen de modéliser et de décrire un algorithme. Vous pouvez décrire les algorithmes comme une série d'étapes discrètes, comme un ensemble de règles à respecter, comme un ensemble de fonctions mathématiques ou comme des objets en interaction. Il est très difficile de concevoir une autre façon de décrire ou de modéliser des algorithmes, et même s'il y en a, je ne suis pas convaincu de son utilité.

Il existe cependant le modèle informatique quantique. En informatique quantique, de nouvelles abstractions sont nécessaires pour modéliser les algorithmes quantiques. Étant néophyte dans ce domaine, je ne peux pas en parler.


4
La programmation orientée vers l'aspect pourrait-elle être considérée comme une autre forme d'abstraction?
Shivan Dragon

La programmation orientée objet est sortie de Lisp dans les années 60? [citation nécessaire], grand temps. Tout ce que j'ai entendu dit qu'il est sorti de Simula dans les années 60, qui était un descendant direct d'ALGOL, un langage impératif qui n'avait rien à voir avec Lisp. Smalltalk est né en prenant les concepts introduits par Simula et en les tordant pour se sentir plus "lispy".
Mason Wheeler

3
@MasonWheeler: C'est dans les manuels Lisp 1 et 1.5, et il est courant d'entendre Lispers parler de faire des programmes orientés objet, en particulier les vieux. Les gars de l'IA étaient grands à faire des systèmes d'objets à Lisp à l'époque.
greyfade

2
@ShivanDragon: Je dirais non. C'est juste un moyen d'instrumenter un programme autrement procédural avec des harnais supplémentaires. Il ne modélise pas vraiment les algorithmes et ne semble pas influencer la conception des structures de données.
greyfade

4
En fait, le calcul du combinateur SKI est antérieur au calcul lambda et à la machine de Turing.
Jörg W Mittag

4

Pour beaucoup, la forme la plus pure d'abstraction de code à l'ère actuelle de la programmation binaire est la "fonction d'ordre supérieur". Fondamentalement, la fonction elle-même est traitée comme des données et les fonctions des fonctions sont définies, tout comme vous les verriez dans des équations mathématiques avec des opérateurs définissant le résultat de leurs opérandes et un ordre prédéterminé d'opérations définissant l '"imbrication" de ces opérations. Les mathématiques ont très très peu de "commandes impératives" dans leur structure; les deux exemples auxquels je peux penser sont "laissez x avoir une valeur ou être une valeur conforme à une certaine contrainte", et "fonctions par morceaux" dans lesquelles l'entrée détermine l'expression nécessaire pour produire la sortie. Ces constructions sont facilement représentables comme leurs propres fonctions; la "fonction" x renvoie toujours 1, et les "surcharges" des fonctions sont définies en fonction de ce qui leur est transmis (qui, contrairement aux surcharges orientées objet, peut être défini en fonction des valeurs entrées) permettant une évaluation "par morceaux" d'un groupe nommé de fonctions, même en termes d'elles-mêmes. En tant que tel, le programme supprime la notion d'impératifs au bas niveau et se concentre plutôt sur l '«auto-évaluation» des données d'entrée données.

Ces fonctions d'ordre supérieur forment l'épine dorsale des "langages fonctionnels"; ce qu'un programme fait est défini en termes de "fonctions pures" (une ou plusieurs entrées, une ou plusieurs sorties, aucun effet secondaire ou "état caché"), qui sont imbriquées les unes dans les autres et évaluées si nécessaire. Dans de tels cas, la plupart des «logiques impératives» sont abstraites; le runtime gère l'appel réel des fonctions et toutes les conditions dans lesquelles l'une ou l'autre surcharge d'une fonction peut devoir être appelée. Dans un tel programme, le code n'est pas considéré comme "faisant" quelque chose, il est considéré comme "étant" quelque chose, et ce qu'il est exactement déterminé lorsque le programme s'exécute avec une entrée initiale.

Les fonctions d'ordre supérieur sont désormais également un aliment de base de nombreux langages impératifs; Les instructions lambda de .NET permettent fondamentalement une entrée fonctionnelle "anonyme" dans une autre "fonction" (implémentée impérativement mais théoriquement cela ne doit pas l'être), permettant ainsi un "chaînage" hautement personnalisable de "fonctions" très générales pour atteindre le résultat souhaité.

Une autre abstraction couramment utilisée dans la dernière série de langages de programmation est le typage de variable dynamique basé sur le concept de "typage du canard"; s'il ressemble à un canard, nage comme un canard, vole comme un canard et charlatans comme un canard, vous pouvez l'appeler un canard. Peu importe que ce soit un canard colvert ou un canvasback. Cela PEUT PEUT-ÊTRE si c'est en fait une oie ou un cygne, mais là encore, cela pourrait ne pas avoir d'importance si tout ce qui vous importe c'est qu'il nage et vole, et ressemble un peu à un canard. Ceci est considéré comme l'ultime héritage d'objet; vous ne vous inquiétez pas ce qu'il est , sauf pour lui donner un nom; ce qui est plus important c'est ce qu'il fait. Dans ces langues, il n'y a essentiellement que deux types; l '"atome", un seul élément d'information (une "valeur"; un nombre, un caractère, une fonction, etc.) et le "tuple", composé d'un atome et d'un "pointeur" pour tout le reste du tuple. La façon exacte dont ces types sont implémentés en binaire par le runtime n'a pas d'importance; En les utilisant, vous pouvez obtenir la fonctionnalité de pratiquement tous les types auxquels vous pouvez penser, des types de valeur simples aux chaînes en passant par les collections (qui, puisque les valeurs peuvent être de différents "types", permettent des "types complexes" aka "objets").


1
Le "typage canard" (du moins comme vous le décrivez) n'est pas vraiment nouveau ni limité aux langages typés dynamiquement; il existe depuis longtemps dans les langages typés statiquement comme "sous-typage structurel", mieux vu dans OCaml.
Tikhon Jelvis

2

On pourrait considérer les langages spécifiques à un domaine comme SQL comme un ordre d'abstraction supérieur. SQL est un langage très ciblé qui résume les opérations telles que le stockage et fournit des fonctions de niveau supérieur basées sur la théorie des ensembles. Considérez également combien de langages traditionnels ne ciblent pas aujourd'hui une architecture spécifique mais plutôt une machine virtuelle (comme la JVM ou le .NET CLR). Par exemple, C # est compilé en IL qui est interprété (ou plus fréquemment JIT'd - Just In Time Compiled-- vers une implémentation native) par le moteur d'exécution natif.

Il y a eu beaucoup de brouhaha sur le concept de DSL utilisé pour créer des langages de très haut niveau qui peuvent être utilisés sans beaucoup d'expérience technique pour créer un programme de travail. Imaginez si quelqu'un était capable de décrire ses entités et ses interactions dans un anglais proche de la langue courante et que l'environnement d'exploitation gérait tout, de la présentation d'une interface utilisateur simple au stockage des données dans une base de données quelconque. Une fois que ces opérations sont devenues abstraites, vous pouvez imaginer à quel point la programmation sans effort peut devenir.

Il en existe aujourd'hui comme JetBrains MPS (qui est une boîte à outils pour décrire les DSL ou un générateur de langage). Microsoft a fait une brève incursion (et je pourrais ajouter très prometteur) dans cet espace avec son langage M (le langage M était si complet que le langage a été défini en M).

Les critiques du concept soulignent les tentatives infructueuses antérieures de retirer les programmeurs du travail de développement de programmes, la différence avec les établis DSL (comme les appelle Fowler) est que les développeurs seraient toujours impliqués dans la codification des concepts que les experts du domaine pourraient utiliser pour exprimer les besoins de leur domaine. Tout comme les fournisseurs de systèmes d'exploitation et de langues créent des outils que nous utilisons pour la programmation, nous utiliserions les DSL pour fournir des outils aux utilisateurs professionnels. On pourrait imaginer des DSL qui décrivent les données et la logique, tandis que les développeurs créent des interprètes qui stockent et récupèrent les données et appliquent la logique exprimée dans le DSL.


1

Je dirais que les méta-structures, les modules, les cadres, les plates-formes et les services sont tous des groupes de fonctionnalités de niveau supérieur aux classes. Ma hiérarchie des abstractions du système de programmation:

  • prestations de service
  • plateformes, piles de solutions
  • cadres
  • modules, packages
  • méta structures: métaclasses, fonctions d'ordre supérieur, génériques, modèles, traits, aspects, décorateurs
  • objets, classes, types de données
  • fonctions, procédures, sous-programmes
  • Structures de contrôle
  • lignes de code

Les méta-structures telles que les métaclasses , les fonctions d'ordre supérieur et les génériques ajoutent clairement une abstraction aux classes, fonctions, types de données et instances de données de base. Les traits, les aspects et les décorateurs sont des mécanismes plus récents pour combiner des fonctionnalités de code et «accélérer» de la même manière d'autres classes et fonctions.

Même les langages pré-objet avaient des modules et des packages, donc les mettre au-dessus des classes pourrait être discutable. Mais ils contiennent ces classes et méta-structures, donc je les classe plus haut.

Les cadres sont la réponse la plus charnue - ils orchestrent plusieurs classes, méta-structures, modules, fonctions et autres afin de fournir des abstractions sophistiquées de haut niveau. Et pourtant, les cadres fonctionnent encore presque entièrement dans le domaine de la programmation.

Les piles de solutions ou les plates-formes combinent généralement plusieurs cadres, sous-systèmes ou composants dans un environnement pour résoudre plusieurs problèmes.

Enfin, il existe des services - souvent déployés en tant que services Web ou de réseau. Ce sont des architectures, des cadres, des piles de solutions ou des capacités d'application fournies sous forme de bundles complets. Leurs composants internes sont souvent opaques, exposant principalement les interfaces administrateur, de programmation et utilisateur. PaaS et SaaS sont des exemples courants.

Or, cette progression peut ne pas être entièrement satisfaisante, pour plusieurs raisons. Tout d'abord, il crée une progression linéaire ou une hiérarchie nette de choses qui ne sont pas parfaitement linéaires ou hiérarchiques. Il couvre certaines abstractions comme les "piles" et les services qui ne sont pas entièrement sous le contrôle des développeurs. Et cela ne pose aucune nouvelle poussière de lutin magique. (Spoiler: Il n'y a pas de poussière de lutin magique. )

Je pense que c'est une erreur de chercher uniquement de nouveaux niveaux d' abstraction . Tous ceux que j'ai énumérés ci-dessus existent depuis des années , même s'ils n'ont pas tous été aussi importants ou populaires qu'ils le sont maintenant. Et au cours de ces années, les abstractions possibles à tous les niveaux de codage se sont améliorées. Nous avons maintenant des collections génériques à usage général, pas seulement des tableaux. Nous parcourons les collections, pas seulement les plages d'index. Nous avons des compréhensions de listes et des opérations de filtrage et de cartographie de listes. De nombreuses fonctions de langage peuvent avoir un nombre variable d'arguments et / ou des arguments par défaut. Etc. Nous augmentons l'abstraction à tous les niveaux, donc l'ajout de niveaux n'est pas une condition pour augmenter le niveau global d'abstraction.


1

L'abstraction suivante après les classes sont des méta-classes . C'est si simple ;)

une classe dont les instances sont des classes. Tout comme une classe ordinaire définit le comportement de certains objets, une métaclasse définit le comportement de certaines classes et de leurs instances. Tous les langages de programmation orientés objet ne prennent pas en charge les métaclasses. Parmi ceux qui le font, la mesure dans laquelle les métaclasses peuvent remplacer un aspect donné du comportement d'une classe varie. Chaque langue a son propre protocole de métaobjet, un ensemble de règles qui régissent la façon dont les objets, les classes et les métaclasses interagissent ...


1
Les métaclasses sont les objets racine de la ou des hiérarchies d'héritage du langage. .NET est un objet. Vous pouvez également considérer les interfaces comme des métaclasses; ils définissent l'interface de leurs héritiers indépendamment de la classe "parent" réelle de l'héritier.
KeithS

1
@KeithS ce n'est pas ce que le mot signifie dans n'importe quel contexte que j'ai vu - de CLOS à UML en C #. Une métaclasse est une classe dont les instances sont des classes - une implémentation faible est C # Typequi donne des capacités de réflexion mais pas de mutation (vous ne pouvez pas ajouter une nouvelle méthode MyTypeen disant typeof(MyType).Methods += new Method ( "Foo", (int x)=>x*x )comme vous pouvez dans CLOS)
Pete Kirkham

1

Je suis surpris que personne n'ait mentionné la théorie des catégories.

L'unité de programmation la plus fondamentale est la fonction qui est basée sur les types. Les fonctions sont généralement désignées par f: A -> B, où A et B sont des types. Si vous mettez ces choses, que j'appelle des types et des fonctions, ensemble dans le bon sens, vous obtenez quelque chose appelé une catégorie. Vous ne devez pas vous arrêter à ce stade.

Prenez ces choses, ces catégories et demandez-vous quelle serait la bonne façon de les relier les unes aux autres. Si vous le faites correctement, vous obtenez quelque chose appelé un foncteur qui va entre deux catégories et est généralement noté F: C -> B. Encore une fois, vous n'avez pas à vous arrêter.

Vous pouvez prendre tous les foncteurs et les assembler de la bonne manière et si vous faites les choses correctement, vous commencez à vous demander comment relier deux foncteurs l'un à l'autre. À ce stade, vous obtenez quelque chose appelé une transformation naturelle, mu: F -> G, où F et G sont des foncteurs.

Ma connaissance à ce stade devient floue, mais vous pouvez continuer à le faire et continuer à gravir les échelons de l'abstraction. Les objets et les classes ne sont même pas près de décrire à quelle hauteur vous pouvez grimper sur l'échelle d'abstraction. Il existe de nombreux langages qui peuvent exprimer les concepts ci-dessus par ordinateur et le plus important de ces langages est Haskell. Donc, si vous voulez vraiment savoir ce qu'est vraiment l'abstraction, allez apprendre Haskell ou Agda ou HOL ou ML.


1

Je pense que le modèle d'acteur est absent de la liste des candidats.

Voici ce que je veux dire par acteurs:

  • entités indépendantes
  • qui reçoivent des messages, et lors de la réception d'un message, peuvent
  • créer de nouveaux acteurs,
  • mettre à jour un état interne pour le prochain message,
  • et envoyer des messages

Ce modèle est quelque chose au-delà des machines déterministes de Turing, et est en fait plus proche de notre matériel du monde réel lorsque l'on regarde des programmes concurrents. À moins que vous n'utilisiez des étapes de synchronisation supplémentaires (coûteuses), de nos jours, lorsque votre code reçoit des données, cette valeur peut déjà avoir changé de l'autre côté du même dé, peut-être même à l'intérieur du même noyau.

Brève discussion / introduction: http://youtube.com/watch?v=7erJ1DV_Tlo


votre message est assez difficile à lire (mur de texte). Cela vous dérangerait de le modifier sous une meilleure forme?
moucher

0

Si je vous comprends bien, vos «abstractions ascendantes» peuvent être considérées comme des encapsulations de plus en plus importantes de logique, principalement liées à la réutilisation de code.

À partir d' instructions spécifiques exécutées les unes après les autres, nous passons à des fonctions / sous-routines , qui encapsulent, ou résument, un regroupement logique d'instructions en un seul élément. Ensuite, nous avons des objets , ou modules , qui encapsulent des sous-programmes relatifs à une certaine entité ou catégorie logique, donc je peux regrouper toutes les opérations de chaîne sous la Stringclasse, ou toutes les opérations mathématiques courantes sous leMath module (ou classe statique, dans des langages tels que C #) .

Donc, si c'est notre progression, quelle est la prochaine étape? Eh bien, je ne pense pas que vous ayez une prochaine étape bien définie. Comme d'autres l'ont répondu, votre progression ne s'applique qu'aux styles de programmation impératifs / procéduraux, et d'autres paradigmes ne partagent pas vos concepts d'abstraction. Mais s'il y a quelque chose qui peut logiquement étendre votre métaphore, ce sont les services .

Un service est similaire à une classe dans le sens où il s'agit d'une entité qui expose des fonctionnalités, mais cela implique une séparation beaucoup plus stricte des préoccupations que le va-et-vient avec des objets que vous avez vous-même instanciés. Ils exposent un ensemble limité d'opérations, masquent la logique interne et ne fonctionnent même pas nécessairement sur la même machine.

Encore une fois, il y a une belle distinction. Dans la plupart des cas, vous utiliserez un objet qui agit en tant que proxy d'un service , et les deux seront très similaires, mais en tant qu'architecture, les deux sont distincts.


0

De nouvelles formes d'abstraction vous cachent un travail de bas niveau. Les procédures et fonctions nommées vous cachent les adresses des programmes. Les objets masquent la gestion dynamique de la mémoire et certaines "instructions if" dépendantes du type.

Je dirais que le prochain niveau d'abstractions pratiques qui vous cachera la corvée de bas niveau est celui de la programmation réactive fonctionnelle . Regardez les "signaux" dans quelque chose comme http://elm-lang.org/ qui cachent les rappels et mettent à jour les dépendances que vous auriez à gérer explicitement en javascript. FRP peut masquer une grande partie de la complexité de la communication inter-processus et inter-machine qui est nécessaire dans les applications Internet à grande échelle et le parallélisme haute performance.

Je suis à peu près sûr que c'est ce qui va nous passionner tous au cours des 5 prochaines années.


1
FRP est génial, mais il traite d'un type de programmation assez spécifique (à savoir la programmation réactive ). Ce n'est pas très bon pour modéliser d'autres types de programmes. Cependant, le type de programmation plus général qu'il représente - écrire votre code en termes d'algèbres - est un bon candidat pour un nouveau niveau d'abstraction.
Tikhon Jelvis

0

Théorie des ensembles - partiellement implémentée dans les bases de données relationnelles, mais aussi dans les langages statistiques comme SAS et R, fournit un niveau d'abstraction différent mais sans doute plus élevé que l'OO.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.