Assert

Why not a function like .... #breakpoint? ?

That would then look very much like an assert.

b = 5
breakpoint? b == 5 ? false : true

Yes/No? I kinda like the question syntax of it.... like should I break?

j.

···

-----Original Message-----
From: Gavin Kistner [mailto:gavin@refinery.com]
Sent: Tue 11/16/2004 6:24 PM
To: ruby-talk ML
Subject: Re: assert

On Nov 12, 2004, at 6:59 PM, Gavin Sinclair wrote:

Now, can anyone suggest a better name than 'assert_bp'?

#break_unless
#break_if

Well, I think

  breakpoint unless b == 5

is clearer. But that's missing the point. Any special method should
have some value over the above statement. Like

  breakpoint_unless 'b == 5'

Would be able to use the string 'b == 5' both to test the condition
with eval and to print a message in the console explaining why the
break has occurred.

That is undoubtedly useful functionality. The question is: what
method name is most acceptable? 'breakpoint_unless' is a bit long (I
don't care, but others probably do). Florian likes 'assume' but I
think that's unclear -- at least it's not clear that it concerns
breakpoints. Also I don't like to introduce too many different method
names to the global namespace.

So I thought of introducing a module, giving us

  Breakpoint.bp_unless
  Breakpoint.bp_if
  Breakpoint.bp_trap # for trapping signals

and whatever other smart things people think of. But that's not
clearly a good idea.

But your post gave me this thought:

  breakpoint? 'b != 5' # breakpoint if b != 5

The question mark suggests "conditional breakpoint", a term we're all
used to from debuggers, I'm sure. That might be the best idea yet.
I'm just not sure which logic to use:

  breakpoint? 'b == 5' # breakpoint unless b == 5

or

  breakpoint? 'b == 5' # breakpoint if b == 5

It's if vs unless. I'll have to think about it, and would appreciate
other peoples' thoughts.

Cheers,
Gavin

···

On Wednesday, November 17, 2004, 8:14:47 PM, Jeff wrote:

Why not a function like .... #breakpoint? ?

That would then look very much like an assert.

b = 5
breakpoint? b == 5 ? false : true

Yes/No? I kinda like the question syntax of it.... like should I break?

Gavin Sinclair wrote:

Why not a function like .... #breakpoint? ?

That would then look very much like an assert.

b = 5
breakpoint? b == 5 ? false : true

Yes/No? I kinda like the question syntax of it.... like should I break?

Well, I think

  breakpoint unless b == 5

is clearer. But that's missing the point. Any special method should
have some value over the above statement. Like

  breakpoint_unless 'b == 5'

How about this:

   def breakpoint
     file, line_no = caller.first.split(':', 2)
     reason = File.readlines(file)[line_no.to_i - 1].
       strip.sub(/^breakpoint\s+/, '')
     p reason
     # setup irb session etc.
   end

   a = 4
   breakpoint unless a == 5

This extracts the "unless a == 5" out of the source file. Of course, that does not work for evaled-code (unless the source-buffer is stored somewhere and we could access it).

But I'm sure, I'm missing something.

Regards,

   Michael

···

On Wednesday, November 17, 2004, 8:14:47 PM, Jeff wrote:

Gavin Sinclair wrote:

The question is: what
method name is most acceptable? 'breakpoint_unless' is a bit long (I
don't care, but others probably do). Florian likes 'assume' but I
think that's unclear -- at least it's not clear that it concerns
breakpoints.

I actually consider that a feature. The interface isn't bound to Breakpoints either. It can make sense to have various actions on a failed assumption and it would be nice if other's could be fit into the same interface.

So I thought of introducing a module, giving us

  Breakpoint.bp_unless
  Breakpoint.bp_if
  Breakpoint.bp_trap # for trapping signals

and whatever other smart things people think of. But that's not
clearly a good idea.

The module already exists. (See Breakpoint.activate_drb) However it is a pain to have methods both inside the Module and in Kernel because that alters the caller's binding.

But your post gave me this thought:

  breakpoint? 'b != 5' # breakpoint if b != 5

The question mark suggests "conditional breakpoint", a term we're all
used to from debuggers, I'm sure. That might be the best idea yet.
I'm just not sure which logic to use:

  breakpoint? 'b == 5' # breakpoint unless b == 5

or

  breakpoint? 'b == 5' # breakpoint if b == 5

Can we have this as an alias for assume()? I like it better than the breakpoint_unless/if forms.

Michael Neumann wrote:

How about this:

  def breakpoint
    file, line_no = caller.first.split(':', 2)
    reason = File.readlines(file)[line_no.to_i - 1].
      strip.sub(/^breakpoint\s+/, '')
    p reason
    # setup irb session etc.
  end

  a = 4
  breakpoint unless a == 5

This extracts the "unless a == 5" out of the source file. Of course, that does not work for evaled-code (unless the source-buffer is stored somewhere and we could access it).

This brings me to an idea I've seen in Python test-cases. They use docstrings before their "asserts", and these docstrings are then use when the assertion fails. Could we do this as well with comments?

(bad example):

Python:

   """Should be > 5"""
   assert(i > 5)

Ruby:

   # Should be > 5
   assert i > 5

This could avoid the use of the message parameter to the assert_* methods, which are used very seldom IMO. One disadvantage of comments is of course, that you can't use #{ ... }.

Regards,

   Michael

Michael Neumann wrote:

How about this:

  def breakpoint
    file, line_no = caller.first.split(':', 2)
    reason = File.readlines(file)[line_no.to_i - 1].
      strip.sub(/^breakpoint\s+/, '')
    p reason
    # setup irb session etc.
  end

  a = 4
  breakpoint unless a == 5

This extracts the "unless a == 5" out of the source file. Of course, that does not work for evaled-code (unless the source-buffer is stored somewhere and we could access it).

I have extracted run-time information from the source code before (proc_source.rb -- it finds the source code of a lambda / lambdafied block) and while it is a nice technique I think the overhead would be too high in this case. (Plus it will not work with -e which is a minor annoyance.)

What overhead are you referring too ?

When an assert bombs, this is an exceptional situation
(supposedly). In such a case I don't mind if the handling
of the exception takes a little while, because I would
rather have more info than less.

BTW: I think that "assert" is a perfect name. That assert()
should re throw an exception or start an irb session should
be a configurable behaviour at run time (i.e. when I am
debugging, it should start an irb session, when in production
it should throw an exception).

There is something I would definitely love to have: The
stack of bindings. So far I can get the binding of the caller
(thanks to some clever code, thanks Florian) and the
"text formatted" caller(). That is not enough. I want to
have a look at the local variables all the way up to the
top of the call stack.

I have begin to develop a work-around but it does not work
yet. It basically uses assert() to store bindings (including
the ones when the assert does not bomb) in a cycling array.
When an assert bombs, it uses the text info from caller() to
try to cross-correlate the recently stored bindings with the
caller() provided call stack. It should work decently in a
mostly single threaded contexts when one calls assert()
frequently enough. This is an heuristic, not 100% reliable.

FWIW.

Yours,

    JeanHuguesRobert

···

At 01:18 18/11/2004 +0900, you wrote:

Michael Neumann wrote:

How about this:
def breakpoint
   file, line_no = caller.first.split(':', 2)
   reason = File.readlines(file)[line_no.to_i - 1].
     strip.sub(/^breakpoint\s+/, '')
   p reason
   # setup irb session etc.
end
a = 4
breakpoint unless a == 5
This extracts the "unless a == 5" out of the source file. Of course, that does not work for evaled-code (unless the source-buffer is stored somewhere and we could access it).

I have extracted run-time information from the source code before (proc_source.rb -- it finds the source code of a lambda / lambdafied block) and while it is a nice technique I think the overhead would be too high in this case. (Plus it will not work with -e which is a minor annoyance.)

-------------------------------------------------------------------------
Web: @jhr is virteal, virtually real
Phone: +33 (0) 4 92 27 74 17

Jean-Hugues ROBERT wrote:

This extracts the "unless a == 5" out of the source file. Of
course, that does not work for evaled-code (unless the
source-buffer is stored somewhere and we could access it).

I have extracted run-time information from the source code before
(proc_source.rb -- it finds the source code of a lambda /
lambdafied block) and while it is a nice technique I think the
overhead would be too high in this case. (Plus it will not work
with -e which is a minor annoyance.)

What overhead are you referring too ?

When an assert bombs, this is an exceptional situation (supposedly).
In such a case I don't mind if the handling of the exception takes a
little while, because I would rather have more info than less.

Oh, I was not referring to performance overhead -- I was talking about
maintenance overhead. It adds a lot of fragile code (at least if you
want to handle code on STDIN, inside an eval, inside irb and so on
properly). I should have been more clear.

BTW: I think that "assert" is a perfect name. That assert() should re
throw an exception or start an irb session should be a configurable
behaviour at run time (i.e. when I am debugging, it should start an
irb session, when in production it should throw an exception).

I agree with this except that assert() has a name clash with test/unit.

There is something I would definitely love to have: The stack of
bindings. So far I can get the binding of the caller (thanks to some
clever code, thanks Florian) and the "text formatted" caller(). That
is not enough. I want to have a look at the local variables all the
way up to the top of the call stack.

You can have this with a custom C extension or a global trace func. The problem with the former is that it would likely be quite slow. The problem with the latter is that it would require a C compiler and that it might have side effects. (I'm pretty sure that the binding of the immediate caller can safely be fetched without causing trouble because eval() does this. I'm not sure about going further up the binding chain.)

I have begin to develop a work-around but it does not work yet. It
basically uses assert() to store bindings (including the ones when
the assert does not bomb) in a cycling array. When an assert bombs,
it uses the text info from caller() to try to cross-correlate the
recently stored bindings with the caller() provided call stack. It
should work decently in a mostly single threaded contexts when one
calls assert() frequently enough. This is an heuristic, not 100%
reliable.

Hm, I wonder if it is worth the hassle. Would it not be simpler to just use a String instead?

I think my current proposed solution to all this looks like this:

- Rename assert() to assume()
- Let assume() take either a block or a code string
- Alias breakpoint?() to assume()

In that case assume() could be omitted in dev-utils though I fear it might cause some confusion. I still need to get final feedback from Gavin. (I hope he is not tired of this yet. It grew to quite a long thread and I am the one to blame for that.)