Basically each lambda compiles into a method body, and the size of its 
lexical environment doesn't matter very much, only the amount of code 
inside the lambda's (fully macroexpanded) body. So in (fn a [x] (foo (letfn 
[(b [] (bar)) (c [] (baz))])), a only "pays for" foo, and b and c pay for 
bar and baz respectively. So the only cause of too-large methods is a 
single large lambda that doesn't delegate to other lambdas.

I checked out midje and tried macroexpanding the test that's giving you 
problems: it expands to 140KB of Clojure source! The culprit is indeed the 
creation of your metadata maps: the :midje/body-source and :midje/source 
keys are each around 40KB literals. I don't know the details of how quoted 
values get put into the bytecode, but it's possible that code is emitted to 
generate them at runtime; perhaps they go into a static initializer, but 
that probably has the same code size limits anyway.

On Monday, February 4, 2013 2:53:04 PM UTC-8, Brian Marick wrote:
>
> An individual Midje "fact" (test case, roughly) macroexpands into a form 
> like this: 
>
>    (record-fact-existence! 
>      (letfn [(fun1 [] ...test code is here...) 
>              (fun2 [] (with-meta fun1 {...metadata...}))] 
>        (fun2)) 
>     
> Tabular facts in Midje are done via unification. A table with 8 rows turns 
> into 8 individual facts (each of that structure), surrounded by an outer 
> level fact that runs each of them. This is wasteful of space but allows 
> unusually expressive tests. 
>
> Something I've done recently seems to have pushed some tabular facts over 
> the Java method-length limit: 
>
> > Caused by: java.lang.ClassFormatError: Invalid method Code length 81209 
> in class file midje/t_checkers$eval24254$this_function_here_24253__24497 
>
> (This is actually surprising, since I don't see what I've done today that 
> could push the size so *much* over 64K.) 
>
> I hope my two breaking tabular facts are atypically large, but I fear not. 
> So, some questions / thoughts: 
>
> 1. Do mutually recursive `letfn` functions get compiled into a single 
> method? More generally, I hope that any nested function definitions turn 
> into separate methods. Do they? 
>
> 2. The metadata is rather large - can it somehow end up increasing the 
> method bytecodes? What if it's constructed via merging literals, like this: 
>
>       (clojure.core/merge 
>        '{:midje/body-source ((+ 1 1) => 2), ...} 
>        {:midje/top-level-fact? true})))] 
>
> The guts of assertion checking also involves merging maps: 
>
>     (check-one (clojure.core/merge 
>                 {:position 
>                  :expected-result-form '2, 
>                  :expected-result 2, 
>                  :function-under-test (clojure.core/fn [] (+ 1 1))} 
>                 {:arrow '=>, :call-form '1} 
>                 (hash-map-duplicates-ok :position (line-number-known 2)))) 
>
> 3. Midje goes to a lot of trouble to obey lexical scoping, so that you can 
> write, for example: 
>
>     (let [a 2] 
>       (fact 
>         (let [b 2] 
>           (+ a b) => (* a b))) 
>
> Do closed-over lexical environments contribute unduly to method size? 
>
> 4. How can I get a look at what a big fact compiles into? (I suppose I 
> need to AOT-compile a test namespace, but I've never had much luck with 
> that.) 
>
> -------- 
> Looking for 1/2-time employment as a Clojure programmer 
> Latest book: /Functional Programming for the Object-Oriented Programmer/ 
> https://leanpub.com/fp-oo 
>
>

-- 
-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to