From maechler at lynne.stat.math.ethz.ch  Mon Jan 26 14:51:39 2015
From: maechler at lynne.stat.math.ethz.ch (Martin Maechler)
Date: Mon, 26 Jan 2015 14:51:39 +0100
Subject: [Rd] speedbump in library
In-Reply-To: <CAOQ5Nyf9fjO0czbDc1U-AtBqkp1N2CtU-AaeMKxA0eqf2N2YKA@mail.gmail.com>
References: <CAGh0NYoAgB-ydT2j0eynAcRMefmL6C3m81dD-a6ZfDmN3kO+tw@mail.gmail.com>
	<CAFOpNVFT3hXcfbDk2fPV2ZyH=NonfZ-Nys05O4E1qWH_kJ8XAA@mail.gmail.com>
	<21702.9915.512807.709742@stat.math.ethz.ch>
	<CAOQ5Nyf9fjO0czbDc1U-AtBqkp1N2CtU-AaeMKxA0eqf2N2YKA@mail.gmail.com>
Message-ID: <21702.18027.398197.522793@stat.math.ethz.ch>

>>>>> Michael Lawrence <lawrence.michael at gene.com>
>>>>>     on Mon, 26 Jan 2015 05:12:55 -0800 writes:

    > A isNamespaceLoaded() function would be a useful thing to
    > have in general if we are interested in readable code. An
    > efficient implementation would be just a bonus.

Good point (readability), and thank you for the support!

Note one slight drawback with your name (which is clearly
better than mine first proposal):
We'd have the three functions named

     isBaseNamespace(ns)
     isNamespace(ns)
     isNamespaceLoaded(name)

where  'name' is really different from 'ns', namely :

  > isNamespace("stats")
  [1] FALSE
  > isNamespace(asNamespace("stats"))
  [1] TRUE

but

  > isNamespaceLoaded("stats")
  [1] TRUE

  > isNamespaceLoaded(asNamespace("stats"))
  Error in as.vector(x, "symbol") : 
    cannot coerce type 'environment' to vector of type 'symbol'
  > 

So, from my (non native English view) a slightly more suggestive
function name may be 

   isLoadedNamespace(name)

or using Luke's original language, still present in the C code,

   isRegisteredNamespace(name)

but I would prefer the former,  isLoadedN..S..()

Martin

    > On Mon, Jan 26, 2015 at 3:36 AM, Martin Maechler
    > <maechler at lynne.stat.math.ethz.ch> wrote:
    >>>>>>> Winston Chang <winstonchang1 at gmail.com> on Fri, 23
    >>>>>>> Jan 2015 10:15:53 -0600 writes:
    >> 
    >> > I think you can simplify a little by replacing this:
    >> 
    >> > pkg %in% loadedNamespaces() > with this: >
    >> .getNamespace(pkg)
    >> 
    >> almost: It would be
    >> 
    >> !is.null(.getNamespace(pkg))
    >> 
    >> > Whereas getNamespace(pkg) will load the package if it's
    >> not already > loaded, calling .getNamespace(pkg) (note
    >> the leading dot) won't load > the package.
    >> 
    >> indeed.  And you, Winston, are right that this new code
    >> snippet would be an order of magnitude faster :
    >> 
    >> ##-----------------------------------------------------------------------------
    >> 
    >> f1 <- function(pkg) pkg %in% loadedNamespaces() f2 <-
    >> function(pkg) !is.null(.getNamespace(pkg))
    >> 
    >> require(microbenchmark)
    >> 
    >> pkg <- "foo"; (mbM <- microbenchmark(r1 <- f1(pkg), r2 <-
    >> f2(pkg))); stopifnot(identical(r1,r2)); r1 ## Unit:
    >> microseconds ## expr min lq mean median uq max neval cld
    >> ## r1 <- f1(pkg) 38.516 40.9790 42.35037 41.7245 42.4060
    >> 82.922 100 b ## r2 <- f2(pkg) 1.331 1.8285 2.13874 2.0855
    >> 2.3365 7.252 100 a ## [1] FALSE
    >> 
    >> pkg <- "stats"; (mbM <- microbenchmark(r1 <- f1(pkg), r2
    >> <- f2(pkg))); stopifnot(identical(r1,r2)); r1 ## Unit:
    >> microseconds ## expr min lq mean median uq max neval cld
    >> ## r1 <- f1(pkg) 29.955 31.2575 32.27748 31.6035 32.1215
    >> 62.428 100 b ## r2 <- f2(pkg) 1.067 1.4315 1.71437 1.6335
    >> 1.8460 9.169 100 a ## [1] TRUE loadNamespace("Matrix") ##
    >> <environment: namespace:Matrix> pkg <- "Matrix"; (mbM <-
    >> microbenchmark(r1 <- f1(pkg), r2 <- f2(pkg)));
    >> stopifnot(identical(r1,r2)); r1 ## Unit: microseconds ##
    >> expr min lq mean median uq max neval cld ## r1 <- f1(pkg)
    >> 32.721 33.5205 35.17450 33.9505 34.6050 65.373 100 b ##
    >> r2 <- f2(pkg) 1.010 1.3750 1.93671 1.5615 1.7795 12.128
    >> 100 a ## [1] TRUE
    >> 
    >> ##-----------------------------------------------------------------------------
    >> 
    >> Hence, indeed, !is.null(.getNamespace(pkg))
    >> 
    >> seems equivalent to pkg %in% loadedNamespaces()
    >> 
    >> --- when 'pkg' is of length 1 (!!!)
    >> 
    >> but is 20 times faster....  and we have 11 occurrences of
    >> ' <...> %in% loadedNamespaces() ' in the "base packages"
    >> in the R (devel) sources, 3 in base, 2 in methods, 3 in
    >> stats, 2 in tools, 1 in utils..
    >> 
    >> On the other hand, pkg %in% loadedNamespaces()
    >> 
    >> is extremely nicely readable code, whereas
    >> !is.null(.getNamespace(pkg)) is pretty much the contrary.
    >> .. and well readable code is so much easier to maintain
    >> etc, such that in many cases, code optimization with the
    >> cost of code obfuscation is *not* desirable.
    >> 
    >> Of course we could yet again use a few lines of C and R
    >> code to provide a new R lowlevel function, say
    >> 
    >> is.loadedNamespace()
    >> 
    >> which would be even faster than
    >> !is.null(.getNamespace(pkg))
    >> 
    >> ...  ...
    >> 
    >> but do we have *any* evidence that this would noticably
    >> speedup any higher level function such as library() ?
    >> 
    >> 
    >> Thank you, again, Winston; you've opened an interesting
    >> topic!
    >> 
    >> --
    >> Martin Maechler, ETH Zurich
    >> 
    >> ______________________________________________
    >> R-devel at r-project.org mailing list
    >> https://stat.ethz.ch/mailman/listinfo/r-devel



[Rd] speedbump in library
Martin Maechler