Lisp HUG Maillist Archive

Conditional dependencies

Hi,

I’m working on a library with a couple of different backends, each with a different set of required libraries. Since not all backends are relevant for all situations, it would be nice to offer users of the lib the possibility to choose which backends to use and avoid loading the dependencies that belong to the unused backends. Is there a good/clean/simple way to achieve this?

Read-time conditionals would be one way to go of course, but I wonder if there are other ways.

Regards
Erik



_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Conditional dependencies



On 14 Feb 2019, at 22:13, Erik Ronström <erik.ronstrom@doremir.com> wrote:

Hi,

I’m working on a library with a couple of different backends, each with a different set of required libraries. Since not all backends are relevant for all situations, it would be nice to offer users of the lib the possibility to choose which backends to use and avoid loading the dependencies that belong to the unused backends. Is there a good/clean/simple way to achieve this?

Read-time conditionals would be one way to go of course, but I wonder if there are other ways.

One good current solution is to use asdf, and to define different systems for the different configurations of backends.

You can define 3 different systems, all depending on a core system, and each on a different backend system.  The core system can use any backend thru a common API. (eg. all backend systems can define a package with the same name as API).


 +-------------+        +-------------+                          
 |  backend-1  |<-------|   system-1  |-----+                    
 +-------------+        +-------------+     |                    
                                            |                    
 +-------------+        +-------------+     +--->+-------------+ 
 |  backend-2  |<-------|   system-2  |--------->|     core    | 
 +-------------+        +-------------+     +--->+-------------+ 
                                            |                    
 +-------------+        +-------------+     |                    
 |  backend-3  |<-------|   system-3  |-----+                    
 +-------------+        +-------------+                          


An alternative, is to merge backend-n with system-n, and just load the system of the backend you want. See for example, portable hemlock:

cl-user> (quick-apropos "hemlock")

#<system hemlock.base / hemlock-20161208-git / quicklisp 2018-10-18> 
#<system hemlock.clx / hemlock-20161208-git / quicklisp 2018-10-18> 
#<system hemlock.qt / hemlock-20161208-git / quicklisp 2018-10-18> 
#<system hemlock.tty / hemlock-20161208-git / quicklisp 2018-10-18> 

You would load one of hemlock.clx, hemlock.qt or hemlock.tty depending on the UI backend you want to use.  Loading hemlock.base (the core) wouldn’t let you do much, since it doesn’t contain an UI.


The fundamental idea is, instead of using read-time conditionals in the sources, use the configuration management system (ie asdf) to select what source to load or not.

-- 
__Pascal J. Bourguignon__




Re: Conditional dependencies

>>>>> On Thu, 14 Feb 2019 22:13:43 +0100, Erik Ronström said:
> 
> Hi,
> 
> I’m working on a library with a couple of different backends, each with a different set of required libraries. Since not all backends are relevant for all situations, it would be nice to offer users of the lib the possibility to choose which backends to use and avoid loading the dependencies that belong to the unused backends. Is there a good/clean/simple way to achieve this?
> 
> Read-time conditionals would be one way to go of course, but I wonder if there are other ways.

For LispWorks defsystem, you could use the :features keyword in the definition
of the members:

(defsystem my-library (:default-type :system)
  :members  ("core-system-1"
             "core-system-2"
             ("optional-system-1" :feature :want-option-1)
             ("optional-system-2" :feature :want-option-2)))

Defsystem evaluates the :feature expression (using *features*) when
compiling/loading the system, rather than at read time.

-- 
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Conditional dependencies

As I understand it real time conditional would not be enough unless there exist some function for each alternative that only spins up the resources for that alternative when/if called for.  The other need that often arises in such cases is for a common overall API to talk to these alternatives uniformly so their differences do not spread to the rest of the system more than necessary.   Microservices fired up from some container is one way to go.  Dynamic loading is another.  

Personally I don't think a whole tree of possible build combinations is the way to go.  Not dynamic enough.  For instance what if the backend are interfaces to different types of database and I would like to dynamically interact with persistent data from more than one of them at the same time?  It gets even more intractable if the set of different backends or other possibilities is not known ahead of time. 


On Thu, Feb 14, 2019 at 2:16 PM Erik Ronström <erik.ronstrom@doremir.com> wrote:
Hi,

I’m working on a library with a couple of different backends, each with a different set of required libraries. Since not all backends are relevant for all situations, it would be nice to offer users of the lib the possibility to choose which backends to use and avoid loading the dependencies that belong to the unused backends. Is there a good/clean/simple way to achieve this?

Read-time conditionals would be one way to go of course, but I wonder if there are other ways.

Regards
Erik



_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Conditional dependencies



On 15 Feb 2019, at 19:26, Samantha Atkins <sjatkins@gmail.com> wrote:

As I understand it real time conditional would not be enough unless there exist some function for each alternative that only spins up the resources for that alternative when/if called for.  The other need that often arises in such cases is for a common overall API to talk to these alternatives uniformly so their differences do not spread to the rest of the system more than necessary.   Microservices fired up from some container is one way to go.  Dynamic loading is another.  

Personally I don't think a whole tree of possible build combinations is the way to go.  Not dynamic enough.  For instance what if the backend are interfaces to different types of database and I would like to dynamically interact with persistent data from more than one of them at the same time?  It gets even more intractable if the set of different backends or other possibilities is not known ahead of time. 


In this case, and assuming you keep the specification that you only want to load what is currently used, you would want some kind of plug-in architecture.
You would compile the different backends into different fasl files, and load them at run-time as needed.
IIRC, asdf has an operation to build a single fasl from a whole system (check the user manual).  Then you would have a separate system for each backend plug-in.

-- 
__Pascal J. Bourguignon__




Updated at: 2020-12-10 08:29 UTC