Loading Multiple Versions of an ASDF System in the Same Lisp Image

Similar documents
INF4820. Common Lisp: Closures and Macros

Common Lisp. Blake McBride

A little bit of Lisp

Robot Programming with Lisp

(defvar *state* nil "The current state: a list of conditions.")

FUNKCIONÁLNÍ A LOGICKÉ PROGRAMOVÁNÍ 4. LISP: PROMĚNNÉ, DALŠÍ VLASTNOSTI FUNKCÍ, BLOKY, MAPOVACÍ FUNKCIONÁLY, ITERAČNÍ CYKLY,

A Genetic Algorithm Implementation

CL-STORE: CL Serialization Package

Inferred System Descriptions ELS <

Lecture #2 Kenneth W. Flynn RPI CS

COSI: Adding Constraints to the object-oriented paradigm

NST: A Unit Test Framework for Common Lisp

Object Oriented Programming (OOP)

A Brief Introduction to Common Lisp

INF4820: Algorithms for Artificial Intelligence and Natural Language Processing. More Common Lisp

FUNKCIONÁLNÍ A LOGICKÉ PROGRAMOVÁNÍ 5. LISP: MAKRA, DATOVÁ STRUKTURA ZÁZNAM

ASDF: Another System Definition Facility

Using a waiting protocol to separate concerns in the mutual exclusion problem

Project 2: Scheme Interpreter

UIOP is a part of ASDF ( which is released under an MIT style License: Copyright c Daniel Barlow and

Allegro CL Certification Program

LISP. Everything in a computer is a string of binary digits, ones and zeros, which everyone calls bits.

Symbolic Computation and Common Lisp

(defun fill-nodes (nodes texts name) (mapcar #'fill-node (replicate-nodes nodes (length texts) name) texts))

Announcement. Overview. LISP: A Quick Overview. Outline of Writing and Running Lisp.

Associative Database Managment WIlensky Chapter 22

CS 842 Ben Cassell University of Waterloo

Associative Database Managment

19 Machine Learning in Lisp

CS 480. Lisp J. Kosecka George Mason University. Lisp Slides

Jigsaw and OSGi: What the Heck Happens Now?

Lisp Basic Example Test Questions

Debugging in LISP. trace causes a trace to be printed for a function when it is called

Common LISP Tutorial 1 (Basic)

Jatha. Common Lisp in Java. Ola Bini JRuby Core Developer ThoughtWorks Studios.

Department of Computer and information Science Norwegian University of Science and Technology

Structure Programming in Lisp. Shared Structure. Tailp. Shared Structure. Top-Level List Structure

ASDF: Another System Definition Facility. Manual for Version

A New Model for Image Distribution

Recursion & Iteration

INF4820: Algorithms for Artificial Intelligence and Natural Language Processing. Common Lisp Fundamentals

Functional Programming. Pure Functional Programming

Common Lisp in the Wild

Common LISP-Introduction

Nothing to see here...

Imperative, OO and Functional Languages A C program is

Introduction to Functional Programming and basic Lisp

CSCI 334: Principles of Programming Languages. Lecture 2: Lisp Wrapup & Fundamentals. Higher-Order Functions. Activity

The Design and Implementation of a Modern Lisp. Dialect

Lambda Calculus and Lambda notation in Lisp II. Based on Prof. Gotshalks notes on Lambda Calculus and Chapter 9 in Wilensky.

Implementing Symmetric Multiprocessing in LispWorks

Functional Programming with Common Lisp

Meet the Macro. a quick introduction to Lisp macros. Patrick Stein / TC Lisp Users Group /

MIDTERM EXAMINATION - CS130 - Spring 2005

a little more on macros sort of like functions, but..

CS 330 Lecture 18. Symbol table. C scope rules. Declarations. Chapter 5 Louden Outline

Common Lisp Object System Specification. 1. Programmer Interface Concepts

June 27, 2014 EuroClojure 2014 Krakow, Poland. Components. Just Enough

Robot Programming with Lisp

Object oriented programming

Symbolic Programming. Dr. Zoran Duric () Symbolic Programming 1/ 89 August 28, / 89

Topic III. LISP : functions, recursion, and lists References: Chapter 3 of Concepts in programming languages by J. C. Mitchell. CUP, 2003.

Modular Java Applications with Spring, dm Server and OSGi

UMBC CMSC 331 Final Exam

Section 10: LISP to Scheme. Evolution of Software Languages

John McCarthy IBM 704

Lambda Calculus. Gunnar Gotshalks LC-1

Comparing JavaBeans and OSGi

CS 360 Programming Languages Interpreters

webpack bundle inner structure and optimization Alexey Ivanov, Evil Martians

OSGi in Action. RICHARD S. HALL KARL PAULS STUART McCULLOCH DAVID SAVAGE CREATING MODULAR APPLICATIONS IN JAVA MANNING. Greenwich (74 w. long.

A Quick Introduction to Common Lisp

Allegro CL Certification Program

Review of Functional Programming

Adding a Module System to Java

CMSC 331 Final Exam Fall 2013

arxiv: v1 [cs.pl] 3 Dec 2014

Lecture Notes on Lisp A Brief Introduction

Lisp: Question 1. Dr. Zoran Duric () Midterm Review 1 1/ 13 September 23, / 13

Lecture #5 Kenneth W. Flynn RPI CS

Artificial Intelligence Programming

AllegroCache. Reference Manual. Franz Inc. version 3.1.2

CSCI B522 Lecture 11 Naming and Scope 8 Oct, 2009

Functional programming techniques

SOFTWARE ARCHITECTURE 6. LISP

Below are example solutions for each of the questions. These are not the only possible answers, but they are the most common ones.

Today. Continue our very basic intro to JavaScript. Lambda calculus

Functional programming with Common Lisp

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End

A JavaScript Framework for Presentations and Animations on Computer Science

CSCI 2210: Programming in Lisp. Progn. Block. CSCI Programming in Lisp; Instructor: Alok Mehta 1. ANSI Common Lisp, Chapters 5-10

1 CLWEB INTRODUCTION 1

Pixel Art Library. Tomi Neste October 31, 2007

Agenda. Why OSGi. What is OSGi. How OSGi Works. Apache projects related to OSGi Progress Software Corporation. All rights reserved.

LFE - a lisp on the Erlang VM

Plug-ins, Modules, and Extensions

Allegro CL Certification Program

Racket: Modules, Contracts, Languages

UMBC CMSC 331 Final Exam Section 0101 December 17, 2002

Lambda Calculus see notes on Lambda Calculus

Transcription:

Loading Multiple Versions of an ASDF System in the Same Lisp Image Vsevolod Domkin 10 th European Lisp Symposium 2017-04-03

It all started with... I'm yet to see a name conflict in Lisp that can't be solved by application of rename-package -- a not-exact quote by Xach Beane (?)

Heard about adversarial learning?

Outline * Dependency Hell problem and solutions * Lisp package system and relevant facilities * ASDF, its APIs & limitations * Conflict scenarios * Our solution to name conflict resolution: its properties, limitations and how it works on/around ASDF * Conclusions and future work

Module name/version conflicts Dependency hell arises around shared packages or libraries on which several other packages have dependencies but where they depend on different and incompatible versions of the shared packages. [Wikipedia] Also known as: dll hell, jar hell

Its manifestation in the CL ecosystem * Unrelated packages' name clashes: reported conflict for bt nickname in Quicklisp (among 1400+ libraries): bordeaux-threads vs binary-types * potential conflict between versions of the same system

Solution in most languages In a particularly sad situation, you may find that you have two dependencies that depend on very incompatible versions of a common transitive dependency. Ideally, you should try to update one of your dependencies to use a newer version of the shared library. If you can t do this, a good backup plan is to unleash a tormented wail and weep into your keyboard. -- The Nine Circles of Python Dependency Hell (https://goo.gl/2wftnh)

Java * custom classloader URLClassLoader clsloader = URLClassLoader.newInstance( new URL[] {new URL("file:/C://Test/test.jar")}); Class cls = clsloader.loadclass("test.main"); Method method = cls.getmethod("main", String[].class); String[]params = new String[2]; method.invoke(null, (Object) params); * OSGi * project Jigsaw

Node.js require Javascript // module.js exports.hello = function() { return "Hello"; } // main.js const mymodule = require('./module'); let val = mymodule.hello(); ES6 imports // module.js export function hello() { return "Hello"; } // main.js import {hello} from 'module'; let val = hello();

Common Lisp Package facility * Packages are centrally-accessible dynamic singleton objects that hold references to symbols * Package namespace is non-hierarchical * Packages may have nicknames * Packages may be redefined and renamed

Idea In the case of a name conflict, use rename-package to alter the name of one the first conflicting package before loading the second one. Potential pitfalls: - conflict discovery - choosing the proper time to rename the package - limits the subsequent use of eval & intern

Common Lisp System facility * Packages provide namespacing, systems provide packaging * ASDF a de facto standard * ASDF in many ways resembles the package system: e.g. find-system is modelled after find-package * Package discovery and distribution built on top of ASDF (see Quicklisp) * A name conflict solution should be built on top of package & system facilities

Limitation of ASDF Likewise with package, it has a central in-memory registry of known systems with a 1-to-1 name-system correspondence. ASDF supports system versioning, but only marginally: - only 1 system version may be known - you can't call find-system with a version argument - ASDF ops (like load-op) may take version as argument, but use it passively (as a constraint)

Critique of ASDF * its ops are not referentiallytransparent and not fully-extensible * it's is a great tool, but it doesn't (yet) realize its potential to become a framework for building on top of it * its mid-level API is not complete, neither it is documented

ASDF can't * load a system from a specific filesystem location * enumerate all potential candidate locations for loading a system * find a system with a specified version * load just the source files for the system's components without potentially reloading its dependencies * read the contents of an ASDF system definition without changing the global state

Basic cases zero (do nothing) basic conflict resolution required

Basic cases (2) subroot cross

Basic cases (3) inter subinter

Algorithm 1.Assemble the dependency tree for the system to be loaded based on ASDF systems' dependency information and, using it, discover the dependencies, which produce name conflicts. 2.In case of no conflicts, fall back to regular ASDF load sequence. 3.In case of conflicts, for each conflicting system determine the topmost possible user that doesn't have two conflicting dependencies.

Algorithm (2) 4.Determine the load order of systems using topological sort with an additional constraint that, among the children of the current node of the dependency tree, the ones that require conflict resolution will be loaded in proper order. 5.Load the system's components (without loading the dependencies) in the determined order recording the fact of visiting a particular system to avoid reloading of the same dependencies.

Algorithm (3) 6.During the load process, record all package additions and associate them with the system being loaded. 7.After a particular system has been loaded, check whether it was determined as a point of renaming for one or more of its dependencies, and perform the renaming (if necessary).

(defun load-system-with-renamings (sys) (multiple-value-bind (deps load-order renamings) (traverse-dep-tree sys) (when (zerop (hash-table-count renamings)) (return-from load-system-with-renamings (asdf:load-system sys))) (let ((already-loaded (make-hash-table :test 'equal)) (dep-packages (make-hash-table))) ;; load dependencies one by one in topological sort ;; order renaming packages when necessary and ;; caching the results (dolist (dep load-order) (let ((conflict (detect-conflict))) (when (or conflict (not (gethash (sys-name dep) already-loaded))) (renaming-packages (if conflict (load-system dep) (load-components (asdf:find-system (sys-name dep))))) (unless conflict (setf (gethash name already-loaded) t)))))))))

(defmacro renaming-packages (&body body) `(let ((known-packages (list-all-packages))),@body ;; record newly added packages (setf (gethash dep dep-packages) (set-difference (list-all-packages) known-packages)) ;; it's safe to rename pending packages now (dolist (d (gethash dep renamings))) (let ((suff (format nil "~:@(~A-~A-~A~)" (sys-version d)(sys-name dep) (gensym)))) (dolist (pkg (gethash d dep-packages)) (rename-package pkg (format nil "~A-~A" (package-name package)suff) (mapcar (lambda (nickname) (format nil "~A-~A" nickname suff)) (package-nicknames pkg))))))

Limitations of this approach * passive capture of package changes * intended for automatic scenarios - may mess up ad hoc interactive workflows * doesn't handle monkey-patching * doesn't handle implicit transitive Dependencies * plus a couple of implementation details

ASDF quiz * How to get a record of a particular ASDF system when you know its.asd file? (asdf:load-asd asd) (cdr (asdf:system-registered-p system))

ASDF quiz (2) * How do you find all candidate.asd systems in your search path? (defun sysdef-exhaustive-central-registry-search (system) (let ((name (asdf:primary-system-name system)) rez) (dolist (dir asdf:*central-registry*) (let ((defaults (eval dir))) (when (and defaults (uiop:directory-pathname-p defaults)) (let ((file (asdf::probe-asd name defaults :truename asdf:*resolve-symlinks*))) (when file (push file rez)))))) (reverse rez))))

ASDF quiz (3) * How do you load just the system's Components without reloading all of its dependencies (and upgrading ASDF in the process)? (defparameter *loading-with-renamings* nil) (defmethod asdf:component-depends-on :around ((o asdf:prepare-op)(s asdf:system)) (unless *loading-with-renamings* (call-next-method))) (defun load-components (sys) (let ((*loading-with-renamings* t)) (dolist (c (asdf:module-components sys)) (asdf:operate 'asdf:load-op c))) t)

Parting words * It works :) * But more work needs to be done to make it not just useful but reusable * ASDFx

Thanks for your attention! Vsevolod Domkin http://vseloved.github.io vseloved @ gmail/twitter/github/ http://m8nware.com (m8n)ware a Lisp company working on cognition-related computing problems