Giter VIP home page Giter VIP logo

proxy-plus's Introduction

proxy-plus

proxy+ is a replacement for Clojure's proxy that's faster and more usable. proxy has a strange implementation where it overrides every possible method and uses a mutable field to store a map of string -> function for dispatching the methods. This causes it to be unable to handle methods with the same name but different arities.

proxy+ fixes these issues with proxy. Usage is like reify, and it's up to 10x faster.

Latest version

The latest release version of proxy-plus is hosted on Clojars:

Current Version

Usage

This library provides the macro proxy+. The first argument is fields to provide to the superclass's constructor. Next comes reify-like definitions to provide overrides. When extending a base class, the base class should come first. Example usage:

(proxy+ [super-arg1 super-arg2]
  BaseClass
  (foo [this] -1)
  (foo [this a b] (+ a b))

  SomeInterface
  (bar [this a b c] (* a b c))

  SomeInterface2
  (bar [this] 100)
  )

Benchmark

The code for this benchmark is in scripts/benchmarks.clj.

proxy one override dispatch performance (10,000 iterations):
------------------------------------------------------------
Evaluation count : 405960 in 60 samples of 6766 calls.
             Execution time mean : 151.149913 µs
    Execution time std-deviation : 3.993821 µs
   Execution time lower quantile : 147.409234 µs ( 2.5%)
   Execution time upper quantile : 162.450275 µs (97.5%)
                   Overhead used : 1.683863 ns

Found 6 outliers in 60 samples (10.0000 %)
	low-severe	 3 (5.0000 %)
	low-mild	 3 (5.0000 %)
 Variance from outliers : 14.1608 % Variance is moderately inflated by outliers


proxy+ one override dispatch performance (10,000 iterations):
-------------------------------------------------------------
Evaluation count : 1126260 in 60 samples of 18771 calls.
             Execution time mean : 54.002204 µs
    Execution time std-deviation : 561.796450 ns
   Execution time lower quantile : 53.246506 µs ( 2.5%)
   Execution time upper quantile : 55.310651 µs (97.5%)
                   Overhead used : 1.683863 ns

Found 3 outliers in 60 samples (5.0000 %)
	low-severe	 3 (5.0000 %)
 Variance from outliers : 1.6389 % Variance is slightly inflated by outliers



proxy ten overrides dispatch performance (10,000 iterations):
-------------------------------------------------------------
Evaluation count : 15780 in 60 samples of 263 calls.
             Execution time mean : 3.835142 ms
    Execution time std-deviation : 53.304494 µs
   Execution time lower quantile : 3.727639 ms ( 2.5%)
   Execution time upper quantile : 3.959029 ms (97.5%)
                   Overhead used : 1.721424 ns

Found 4 outliers in 60 samples (6.6667 %)
	low-severe	 1 (1.6667 %)
	low-mild	 3 (5.0000 %)
 Variance from outliers : 1.6389 % Variance is slightly inflated by outliers


proxy+ ten overrides dispatch performance (10,000 iterations):
--------------------------------------------------------------
Evaluation count : 146280 in 60 samples of 2438 calls.
             Execution time mean : 416.130110 µs
    Execution time std-deviation : 7.529965 µs
   Execution time lower quantile : 406.496697 µs ( 2.5%)
   Execution time upper quantile : 431.908321 µs (97.5%)
                   Overhead used : 1.721424 ns

Found 7 outliers in 60 samples (11.6667 %)
	low-severe	 7 (11.6667 %)
 Variance from outliers : 7.7810 % Variance is slightly inflated by outliers

License

Copyright 2020 Red Planet Labs, Inc. proxy-plus is licensed under Apache License v2.0.

proxy-plus's People

Contributors

atdixon avatar bryanduxbury avatar hugoduncan avatar jeff303 avatar nathanmarz avatar nixin72 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

proxy-plus's Issues

How can I use this with custom methods or clojure protocols?

Hello,

I am trying to extend an abstract class and also implement custom methods (not belonging to an interface / abstract class).
Is this possible?

I tried but it failed with error.

I also tried defining a protocol:

(defprotocol ICsvTable
  "Some extra CSV table methods"
  (isStream [this] "Return true if table is stream")
  (getFieldTypes [this type-factory] "Returns the field types of this CSV table."))

(defn csv-table
  [^Source source ^RelProtoDataType proto-row-type]
  (let [field-types (ArrayList.)])
  (proxy+ []
          AbstractTable
          (getRowType
           [this type-factory]
           (get-row-type this source type-factory proto-row-type row-type proto-row-type))
          ICsvTable
          (isStream [this] false)
          (getFieldTypes
           [this type-factory]
           (when (.isEmpty field-types)
             (CsvEnumerator/deduceRowType type-factory source field-types (.isStream this))))))

and I got this (cryptic) error message:

; Evaluating file: calcite_csv.clj
; Syntax error macroexpanding proxy+ at (src/ro/ieugen/calcite_csv.clj:76:3).
; No implementation of method: :asm-type of protocol: #'com.rpl.asm/ASMType found for class: clojure.lang.Var
; Evaluation of file calcite_csv.clj failed: class clojure.lang.Compiler$CompilerException

Can't use classes generated from AOT

Awesome project!

There is a issue though, only when the class was generated from AOT, when I try to use it I get a exception

(ns foo)
(proxy+ Foo
        []
        java.util.Date
        (toString [_] "foo"))
(.toString (com.github.clojure_lsp.intellij.extension.formatting.Foo.)) ;; throws exception only when class was generated from AOT
java.lang.NullPointerException: Cannot invoke "clojure.lang.IFn.invoke(Object)" because "this.toString13132" is null
 at foo.Foo.toString (:-1)

Ergonomic Hints

It can be frustrating to work out what type signatures are available. It'd be helpful to include a list of options on errors (demo: https://github.com/owenRiddy/proxy-plus-minus/blob/main/src/proxy_plus_minus/core.clj#L122).

What this looks like using the proposed custom hinting from Issue #20 :

          (proxy+ [] TestBaseClass3
                  (trickyCase [this a b] [char java.lang.String :=> int] 8))
=>
Caused by: clojure.lang.ExceptionInfo: No matching methods {:base testclasses.TestBaseClass3, 
:name "trickyCase", 
:param-type [char java.lang.String :=> int],
 :param-type-options (["finalize" [:=> void]] ["clone" [:=> java.lang.Object]] 
["getInt" [:=> java.lang.Integer]] ["getDouble" [int double java.lang.String java.lang.Integer boolean :=> double]] 
["getString" [java.lang.String :=> java.lang.String]] ["getOtherInt" [:=> int]] 
["trickyCase" [int java.lang.String :=> int]] ["trickyCase" [java.lang.Integer java.lang.String :=> int]] 
["wait" [long int :=> void]] 
["wait" [:=> void]] ["wait" [long :=> void]] ["equals" [java.lang.Object :=> boolean]] 
["toString" [:=> java.lang.String]] ["hashCode" [:=> int]] ["getClass" [:=> java.lang.Class]]
 ["notify" [:=> void]]
 ["notifyAll" [:=> void]])}

;; Programmer thinks: 'Aha! I want ["trickyCase" [int java.lang.String :=> int]] 
;;       so I should use [int java.lang.String :=> int]'

Dependencies not available on Maven central

This doesn't work with deps.edn if you just add the dependency as is:

Error building classpath. Could not find artifact com.rpl:rama-shaded-asm:jar:4.2 in central (https://repo1.maven.org/maven2/)

unless you add a :mvn/repos entry like

{:mvn/repos {"rpl" {:url "https://nexus.redplanetlabs.com/repository/maven-public-releases"}}}

but this has downsides, since adding the extra maven repo has to be done for anything upstream that might be using something using this library.

Any chance you can add the dependency to Clojars as well? If not, it's probably worth calling this out in the README so other people don't get tripped up on it

Upgrade to latest (newer) asm library - support newer jdk's

Hello,

ASM has eveloved, the current release is from 2013.
New versions support newer JDK releases. See https://asm.ow2.io/versions.html .

I did upgrade locally and it builds and the tests pass - but did not try any code against other jvm's .

Perhaps an automated build to test against multiple JVM might be a good option.

(⎈ |libris-k2-admin:prod)ieugen@daos-495:~/.../clojure/proxy-plus$ lein test
Retrieving org/ow2/asm/asm/9.2/asm-9.2.pom from central
Retrieving org/ow2/asm/asm-commons/9.2/asm-commons-9.2.pom from central
Retrieving org/ow2/asm/asm-tree/9.2/asm-tree-9.2.pom from central
Retrieving org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2.pom from central
Retrieving org/ow2/asm/asm-util/9.2/asm-util-9.2.pom from central
Retrieving org/ow2/asm/asm-commons/9.2/asm-commons-9.2.jar from central
Retrieving org/ow2/asm/asm-tree/9.2/asm-tree-9.2.jar from central
Retrieving org/ow2/asm/asm-util/9.2/asm-util-9.2.jar from central
Retrieving org/ow2/asm/asm/9.2/asm-9.2.jar from central
Retrieving org/ow2/asm/asm-analysis/9.2/asm-analysis-9.2.jar from central

lein test com.rpl.proxy-plus-test

Ran 13 tests containing 52 assertions.
0 failures, 0 errors.

Multiple constructors with the same arity can cause reflection

Here's a (silly) example:

user=> (import java.io.File)
java.io.File
user=> (defn mkfile [^String pathname] (proxy+ [pathname] File))
Reflection warning, NO_SOURCE_PATH:1:33 - call to user.proxy_plus6169 ctor can't be resolved.
#'user/mkfile

The problem only occurs when multiple constructors have the same arity. I think the problem goes away if you type hint (as java.util.Map) the function map which is passed when invoking the constructor.

Support for proxy-super equivalent

Would be nice to have an equivalent to Clojure's proxy-super. May or may not be possible to do efficiently. One idea is to wrap the call to super in a lambda and make the lambda available to the clojure body code via a binding.

Tricky Edge Cases

Hi again. I have detected a tricky edge case. I'm don't know Java very well, so bear with me if I get something wrong here:

public class TestBaseClass3{
    public int trickyCase(int a, String b) {
        return 6;
    }

    public int trickyCase(java.lang.Integer a, String b) {
        return 7;
    }
}

It is trickey to override the trickyCase that returns 6.

(proxy+ [] TestBaseClass3
                  ;; Impossible: "Only long and double primitives are supported"
                   (trickyCase [this ^int a b] 8))

I propose that there should be an option to explicitly declare the type signatures independent of hints. I found something like (trickyCase [this a b] [int java.lang.String :=> int] ...) ergonomic (example: https://github.com/owenRiddy/proxy-plus-minus/blob/main/test/clj/proxy_plus_minus/core_test.clj#L276).

If you like the idea I can put together a PR for proxy-plus.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.