É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?
programming-languages
object-oriented
language-agnostic
abstraction
Jordan Medlock
la source
la source
Réponses:
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.
la source
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").
la source
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.
la source
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:
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.
la source
L'abstraction suivante après les classes sont des méta-classes . C'est si simple ;)
la source
Type
qui donne des capacités de réflexion mais pas de mutation (vous ne pouvez pas ajouter une nouvelle méthodeMyType
en disanttypeof(MyType).Methods += new Method ( "Foo", (int x)=>x*x )
comme vous pouvez dans CLOS)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.
la source
Je pense que le modèle d'acteur est absent de la liste des candidats.
Voici ce que je veux dire par acteurs:
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
la source
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
String
classe, 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.
la source
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.
la source
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.
la source