unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* expression
@ 2010-06-23 21:09 Michael Lucy
  2010-06-23 23:14 ` expression No Itisnt
  2010-06-24  6:55 ` expression Ken Raeburn
  0 siblings, 2 replies; 10+ messages in thread
From: Michael Lucy @ 2010-06-23 21:09 UTC (permalink / raw)
  To: guile-devel

Hey,

Is there any scheme expression that will just get ignored when the
scheme code is compiled?

I'm generating some code with a function like:

(define (gen-update-ab updatea updateb)
  `(begin
     ,(if updatea `(set! a (+ a 1)) `(donothing))
     ,(if updateb `(set! b (+ b 1)) `(donothing))))

And ideally I could replace the donothing function with something that
will get discarded during compilation.

There are alternatives, but they're pretty ugly (significantly moreso
in my actual code than they look below):

(define (gen-update-ab-2 updatea updateb)
  `(begin
     ,@(if updatea `((set! a (+ a 1))) `())
     ,@(if updateb `((set! b (+ b 1))) `())))

(define (gen-update-ab-3 updatea updateb)
  (filter (lambda (x) (not (null? x)))
          `(begin
             ,(if updatea `(set! a (+ a 1)) `())
             ,(if updateb `(set! b (+ b 1)) `()))))



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: expression
  2010-06-23 21:09 expression Michael Lucy
@ 2010-06-23 23:14 ` No Itisnt
  2010-06-23 23:23   ` expression Michael Lucy
  2010-06-24  6:55 ` expression Ken Raeburn
  1 sibling, 1 reply; 10+ messages in thread
From: No Itisnt @ 2010-06-23 23:14 UTC (permalink / raw)
  To: Michael Lucy; +Cc: guile-devel

On Wed, Jun 23, 2010 at 4:09 PM, Michael Lucy <MichaelGLucy@gmail.com> wrote:
> Hey,
>
> Is there any scheme expression that will just get ignored when the
> scheme code is compiled?
>
> I'm generating some code with a function like:
>
> (define (gen-update-ab updatea updateb)
>  `(begin
>     ,(if updatea `(set! a (+ a 1)) `(donothing))
>     ,(if updateb `(set! b (+ b 1)) `(donothing))))
>
> And ideally I could replace the donothing function with something that
> will get discarded during compilation.

I'm not sure if Guile will discard the result, but I think
*unspecified* is the idiomatic value for those sorts of situations.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: expression
  2010-06-23 23:14 ` expression No Itisnt
@ 2010-06-23 23:23   ` Michael Lucy
  2010-06-24 13:01     ` expression Andy Wingo
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Lucy @ 2010-06-23 23:23 UTC (permalink / raw)
  To: No Itisnt; +Cc: guile-devel

Doesn't look like it ignores it:

scheme@(guile-user)> ,c (begin (set! x 1))
Disassembly of #<objcode bdc6e48>:

   0    (assert-nargs-ee/locals 0)
   2    (make-int8:1)                   ;; 1
   3    (load-symbol "x")               ;; x
   8    (link-now)
   9    (variable-set)
  10    (void)
  11    (return)

scheme@(guile-user)> ,c (begin (set! x 1) *unspecified*)
Disassembly of #<objcode 9a05d08>:

   0    (assert-nargs-ee/locals 0)
   2    (make-int8:1)                   ;; 1
   3    (load-symbol "x")               ;; x
   8    (link-now)
   9    (variable-set)
  10    (load-symbol "*unspecified*")   ;; *unspecified*
  27    (link-now)
  28    (variable-ref)
  29    (return)

scheme@(guile-user)>

If it's idiomatic I'll do that till I find something else though.  Thanks!

On Wed, Jun 23, 2010 at 6:14 PM, No Itisnt <theseaisinhere@gmail.com> wrote:
> On Wed, Jun 23, 2010 at 4:09 PM, Michael Lucy <MichaelGLucy@gmail.com> wrote:
>> Hey,
>>
>> Is there any scheme expression that will just get ignored when the
>> scheme code is compiled?
>>
>> I'm generating some code with a function like:
>>
>> (define (gen-update-ab updatea updateb)
>>  `(begin
>>     ,(if updatea `(set! a (+ a 1)) `(donothing))
>>     ,(if updateb `(set! b (+ b 1)) `(donothing))))
>>
>> And ideally I could replace the donothing function with something that
>> will get discarded during compilation.
>
> I'm not sure if Guile will discard the result, but I think
> *unspecified* is the idiomatic value for those sorts of situations.
>



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: expression
  2010-06-23 21:09 expression Michael Lucy
  2010-06-23 23:14 ` expression No Itisnt
@ 2010-06-24  6:55 ` Ken Raeburn
  2010-06-24  7:27   ` expression Thien-Thi Nguyen
                     ` (2 more replies)
  1 sibling, 3 replies; 10+ messages in thread
From: Ken Raeburn @ 2010-06-24  6:55 UTC (permalink / raw)
  To: Michael Lucy; +Cc: guile-devel

On Jun 23, 2010, at 17:09, Michael Lucy wrote:
> Is there any scheme expression that will just get ignored when the
> scheme code is compiled?
> 
> I'm generating some code with a function like:
> 
> (define (gen-update-ab updatea updateb)
>  `(begin
>     ,(if updatea `(set! a (+ a 1)) `(donothing))
>     ,(if updateb `(set! b (+ b 1)) `(donothing))))
> 
> And ideally I could replace the donothing function with something that
> will get discarded during compilation.

A simple constant like #f or '() or 42 shouldn't cause any evaluation to happen, unless it's the last expression and thus the value to be returned (in which case you'd just be returning a simple constant).

I don't know if there's a canonical efficient way to generate it, but it looks like "(if #f #f)" will be optimized by the current compiler into just pushing the magic "undefined value" onto the stack.  Getting rid of the push altogether *IF* the result of the expression is unused is up to the optimizer; you shouldn't be jumping through hoops in the code you generate to make that happen.  But it appears that it does happen at least in simple cases:

scheme@(guile-user)> ,c (begin (if #f #f) (if #f #f) 42)
Disassembly of #<objcode 101678308>:

   0    (assert-nargs-ee/locals 0)      
   2    (make-int8 42)                  ;; 42
   4    (return)                        

Hmm... here's another way, though I've no idea if RnRS lets you not have any expressions in here:

scheme@(guile-user)> ,c (begin)                            
Disassembly of #<objcode 10163f848>:

   0    (assert-nargs-ee/locals 0)      
   2    (void)                          
   3    (return)              

scheme@(guile-user)> ,c (begin (begin) (begin) 42)
Disassembly of #<objcode 1016782a8>:

   0    (assert-nargs-ee/locals 0)      
   2    (make-int8 42)                  ;; 42
   4    (return)                        


> There are alternatives, but they're pretty ugly (significantly moreso
> in my actual code than they look below):

Depends how you define ugliness. :-)

Your approach expands each possible update into one S-expression.  So you need *something* there for each one, even if it's just a constant, or an empty "begin".

The alternative, I think, is rearranging your code so that no expression gets added to the list when there's nothing to do; one way to do that, off the top of my head, would be to generate a possibly-empty list of expressions rather than exactly one for each possible update, and then merge the lists together.  Or start with an empty list, and tack S-expressions on the front for updates that are needed, then add the "begin" and return the result.

But in terms of the generated byte code, the constants should just go away if they're not actually used, and nested "begin" lists should get flattened, so I don't think it should matter much either way.

If you want the macro expansion to be human-readable for debugging purposes, you could also consider putting in some kind of no-op annotation that shouldn't generate code, for example a let loop with a meaningful label name and no useful body, or wrapping code that actually has effects but doesn't use the label:

scheme@(guile-user)> ,c (begin (let no-update-needed-for-a () #f) 42)
Disassembly of #<objcode 1030dc468>:

   0    (assert-nargs-ee/locals 0)      
   2    (br :L171)                      ;; -> 10
   6    (br :L172)                      ;; -> 14
  10    (br :L173)                      ;; -> 6
  14    (make-int8 42)                  ;; 42
  16    (return)                        

Ehh... okay, maybe there's a little work to be done for that one. :-)

Ken


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: expression
  2010-06-24  6:55 ` expression Ken Raeburn
@ 2010-06-24  7:27   ` Thien-Thi Nguyen
  2010-06-24  7:52   ` expression Michael Lucy
  2010-06-24 13:03   ` expression Andy Wingo
  2 siblings, 0 replies; 10+ messages in thread
From: Thien-Thi Nguyen @ 2010-06-24  7:27 UTC (permalink / raw)
  To: guile-devel

() Ken Raeburn <raeburn@raeburn.org>
() Thu, 24 Jun 2010 02:55:59 -0400

   Hmm... here's another way, though I've no idea if RnRS lets you not have
   any expressions in here:

   scheme@(guile-user)> ,c (begin)                            
   Disassembly of #<objcode 10163f848>:

      0    (assert-nargs-ee/locals 0)      
      2    (void)                          
      3    (return)              

   scheme@(guile-user)> ,c (begin (begin) (begin) 42)
   Disassembly of #<objcode 1016782a8>:

      0    (assert-nargs-ee/locals 0)      
      2    (make-int8 42)                  ;; 42
      4    (return)                        

I think this is fine.  ‘(begin)’ is how things (and "no things") are spliced.

thi



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: expression
  2010-06-24  6:55 ` expression Ken Raeburn
  2010-06-24  7:27   ` expression Thien-Thi Nguyen
@ 2010-06-24  7:52   ` Michael Lucy
  2010-06-24 13:05     ` expression Andy Wingo
  2010-06-24 13:03   ` expression Andy Wingo
  2 siblings, 1 reply; 10+ messages in thread
From: Michael Lucy @ 2010-06-24  7:52 UTC (permalink / raw)
  To: Ken Raeburn; +Cc: guile-devel

On Thu, Jun 24, 2010 at 1:55 AM, Ken Raeburn <raeburn@raeburn.org> wrote:
> On Jun 23, 2010, at 17:09, Michael Lucy wrote:
>> Is there any scheme expression that will just get ignored when the
>> scheme code is compiled?
>>
>> I'm generating some code with a function like:
>>
>> (define (gen-update-ab updatea updateb)
>>  `(begin
>>     ,(if updatea `(set! a (+ a 1)) `(donothing))
>>     ,(if updateb `(set! b (+ b 1)) `(donothing))))
>>
>> And ideally I could replace the donothing function with something that
>> will get discarded during compilation.
>
> A simple constant like #f or '() or 42 shouldn't cause any evaluation to happen, unless it's the last expression and thus the value to be returned (in which case you'd just be returning a simple constant).

Ah, I see.  I tried that with variables, and just assumed that if they
weren't optimized out constants wouldn't be either (in retrospect not
such a great assumption):

scheme@(guile-user)> ,c (begin a b 1)
Disassembly of #<objcode d123d28>:

   0    (assert-nargs-ee/locals 0)
   2    (load-symbol "a")               ;; a
   7    (link-now)
   8    (variable-ref)
   9    (drop)
  10    (load-symbol "b")               ;; b
  15    (link-now)
  16    (variable-ref)
  17    (drop)
  18    (make-int8:1)                   ;; 1
  19    (return)

Out of curiosity, why are variables left in?  Are there situations
where evaluating a variable will have side-effects?

Anyway, thanks!  That makes life a lot simpler.

>
> I don't know if there's a canonical efficient way to generate it, but it looks like "(if #f #f)" will be optimized by the current compiler into just pushing the magic "undefined value" onto the stack.  Getting rid of the push altogether *IF* the result of the expression is unused is up to the optimizer; you shouldn't be jumping through hoops in the code you generate to make that happen.  But it appears that it does happen at least in simple cases:
>
> scheme@(guile-user)> ,c (begin (if #f #f) (if #f #f) 42)
> Disassembly of #<objcode 101678308>:
>
>   0    (assert-nargs-ee/locals 0)
>   2    (make-int8 42)                  ;; 42
>   4    (return)
>
> Hmm... here's another way, though I've no idea if RnRS lets you not have any expressions in here:
>
> scheme@(guile-user)> ,c (begin)
> Disassembly of #<objcode 10163f848>:
>
>   0    (assert-nargs-ee/locals 0)
>   2    (void)
>   3    (return)
>
> scheme@(guile-user)> ,c (begin (begin) (begin) 42)
> Disassembly of #<objcode 1016782a8>:
>
>   0    (assert-nargs-ee/locals 0)
>   2    (make-int8 42)                  ;; 42
>   4    (return)
>
>
>> There are alternatives, but they're pretty ugly (significantly moreso
>> in my actual code than they look below):
>
> Depends how you define ugliness. :-)
>
> Your approach expands each possible update into one S-expression.  So you need *something* there for each one, even if it's just a constant, or an empty "begin".
>
> The alternative, I think, is rearranging your code so that no expression gets added to the list when there's nothing to do; one way to do that, off the top of my head, would be to generate a possibly-empty list of expressions rather than exactly one for each possible update, and then merge the lists together.  Or start with an empty list, and tack S-expressions on the front for updates that are needed, then add the "begin" and return the result.
>
> But in terms of the generated byte code, the constants should just go away if they're not actually used, and nested "begin" lists should get flattened, so I don't think it should matter much either way.
>
> If you want the macro expansion to be human-readable for debugging purposes, you could also consider putting in some kind of no-op annotation that shouldn't generate code, for example a let loop with a meaningful label name and no useful body, or wrapping code that actually has effects but doesn't use the label:
>
> scheme@(guile-user)> ,c (begin (let no-update-needed-for-a () #f) 42)
> Disassembly of #<objcode 1030dc468>:
>
>   0    (assert-nargs-ee/locals 0)
>   2    (br :L171)                      ;; -> 10
>   6    (br :L172)                      ;; -> 14
>  10    (br :L173)                      ;; -> 6
>  14    (make-int8 42)                  ;; 42
>  16    (return)
>
> Ehh... okay, maybe there's a little work to be done for that one. :-)
>
> Ken



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: expression
  2010-06-23 23:23   ` expression Michael Lucy
@ 2010-06-24 13:01     ` Andy Wingo
  0 siblings, 0 replies; 10+ messages in thread
From: Andy Wingo @ 2010-06-24 13:01 UTC (permalink / raw)
  To: Michael Lucy; +Cc: guile-devel, No Itisnt

Hi Michael,

On Thu 24 Jun 2010 01:23, Michael Lucy <MichaelGLucy@Gmail.com> writes:

> scheme@(guile-user)> ,c (begin (set! x 1) *unspecified*)
> Disassembly of #<objcode 9a05d08>:
>
>    0    (assert-nargs-ee/locals 0)
>    2    (make-int8:1)                   ;; 1
>    3    (load-symbol "x")               ;; x
>    8    (link-now)
>    9    (variable-set)
>   10    (load-symbol "*unspecified*")   ;; *unspecified*
>   27    (link-now)
>   28    (variable-ref)
>   29    (return)

In current Guile, *unspecified* is actually a macro, allowing the
compiler to do its job better:

scheme@(guile-user)> ,c (begin (set! x 1) *unspecified*)
<stdin>:1:10: warning: possibly unbound variable `x'
Disassembly of #<objcode 94a1908>:

   0    (assert-nargs-ee/locals 0)      
   2    (make-int8:1)                   ;; 1
   3    (load-symbol "x")               ;; x
   8    (link-now)                      
   9    (variable-set)                  
  10    (void)                          
  11    (return)                        

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: expression
  2010-06-24  6:55 ` expression Ken Raeburn
  2010-06-24  7:27   ` expression Thien-Thi Nguyen
  2010-06-24  7:52   ` expression Michael Lucy
@ 2010-06-24 13:03   ` Andy Wingo
  2010-06-24 14:40     ` expression Ken Raeburn
  2 siblings, 1 reply; 10+ messages in thread
From: Andy Wingo @ 2010-06-24 13:03 UTC (permalink / raw)
  To: Ken Raeburn; +Cc: Michael Lucy, guile-devel

On Thu 24 Jun 2010 08:55, Ken Raeburn <raeburn@raeburn.org> writes:

> Hmm... here's another way, though I've no idea if RnRS lets you not have
> any expressions in here:
>
> scheme@(guile-user)> ,c (begin)

There are actually two kinds of begin: one in definition context and one
in expression context. The former takes 0 or more forms, and splices
those forms into the input, where the (begin ...) appears. The other
takes 1 or more expressions, and evaluates those expression in order,
returning the value of the last.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: expression
  2010-06-24  7:52   ` expression Michael Lucy
@ 2010-06-24 13:05     ` Andy Wingo
  0 siblings, 0 replies; 10+ messages in thread
From: Andy Wingo @ 2010-06-24 13:05 UTC (permalink / raw)
  To: Michael Lucy; +Cc: Ken Raeburn, guile-devel

Hi,

On Thu 24 Jun 2010 09:52, Michael Lucy <MichaelGLucy@Gmail.com> writes:

> scheme@(guile-user)> ,c (begin a b 1)
> Disassembly of #<objcode d123d28>:
>
>    0    (assert-nargs-ee/locals 0)
>    2    (load-symbol "a")               ;; a
>    7    (link-now)
>    8    (variable-ref)
>    9    (drop)
>   10    (load-symbol "b")               ;; b
>   15    (link-now)
>   16    (variable-ref)
>   17    (drop)
>   18    (make-int8:1)                   ;; 1
>   19    (return)
>
> Out of curiosity, why are variables left in?  Are there situations
> where evaluating a variable will have side-effects?

Global variable references can cause side effects (exceptions, module
autoloads, binders, duplicates handlers, etc) so they are not optimized
out. Lexical references cannot cause side effects, so they are optimized
out.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: expression
  2010-06-24 13:03   ` expression Andy Wingo
@ 2010-06-24 14:40     ` Ken Raeburn
  0 siblings, 0 replies; 10+ messages in thread
From: Ken Raeburn @ 2010-06-24 14:40 UTC (permalink / raw)
  To: Andy Wingo; +Cc: Michael Lucy, guile-devel

On Jun 24, 2010, at 09:03, Andy Wingo wrote:
> There are actually two kinds of begin: one in definition context and one
> in expression context. The former takes 0 or more forms, and splices
> those forms into the input, where the (begin ...) appears. The other
> takes 1 or more expressions, and evaluates those expression in order,
> returning the value of the last.

Ah, right... so my example was presumably in definition context, so having no additional forms was okay, but Michael's use is probably expression context, where it wouldn't, making my suggestion no good... good to know. :-)  Thanks for the correction.

And "*unspecified*" references are optimized by the compiler now?  Great!  Then "No Itisnt"'s suggestion looks like the right way to go after all...

Ken


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2010-06-24 14:40 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-23 21:09 expression Michael Lucy
2010-06-23 23:14 ` expression No Itisnt
2010-06-23 23:23   ` expression Michael Lucy
2010-06-24 13:01     ` expression Andy Wingo
2010-06-24  6:55 ` expression Ken Raeburn
2010-06-24  7:27   ` expression Thien-Thi Nguyen
2010-06-24  7:52   ` expression Michael Lucy
2010-06-24 13:05     ` expression Andy Wingo
2010-06-24 13:03   ` expression Andy Wingo
2010-06-24 14:40     ` expression Ken Raeburn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).