Duck Typing and automated Conversions

The fact that String#to_str returns self, and Fixnum.to_int returns self, is
purely coincidental aliasing (from inside your method body). The original
parm-list variables might as well be anonymous.

···

"Robert Klemme" <bob.news@gmx.net> wrote

> silly_example will not have other access to x, y
> (*: since you did: str=str.to_str; count=count.to_int)

Wrong, because to_str need not create a new instance:

Hi,

I think I probably was somewhat unclear in my other post. I wasn't
arguing for or against your idea (for the most part), I was going off
it and thinking up a related idea... I guess it was actually pretty
off topic.

"Mark Hubbart" <discordantus@gmail.com> schrieb im Newsbeitrag
news:de63abca0501141100154206a8@mail.gmail.com...

> I do this to make sure I'm allowing for maximum flexibility, or when
> working with other's code, to find out what the actual requirements
> are :slight_smile:

Well, then you'll learn that your instance must implement to_int. Same as
if someone had coded that directly in the method. I don't see this as an
argument against my suggested shortcut syntax, because that mainly affects
the *writer* of a method - not the *caller*.

My only argument against the shortcut syntax is that I can't see how
often it could be used, except to simulate static typing. I suspect
that adding a feature like this would encourage the use of static
typing in methods.

In your example method, you called #to_int on an object that you were
just going to call #times on. This doesn't guarantee that you will get
an integer, and makes it difficult for others to use duck typing in
code that interfaces with yours. In fact, if they need the
functionality, then the have to resort to some hack like this:

obj = ObjectThatImplementsTimes.new
wrapper = Object.new
class << wrapper;self;end.__send__(:define_method, :to_int){obj}

A very ugly hack, just to re-allow duck typing.

> There are a couple of problems still: First, an object might still be
> able to respond to a message, using method_missing, but #respond_to?
> won't show it.

You introduced the #respond_to? - my suggestion was to simply invoke it and
see what happens (duck typing).

I was describing something else; I was describing a possible problem
with *my* implementation of a related idea. OT, I know :confused:

> Second, I'm not sure about the syntax. It would work
> (it currently give a parse error), but I think something better and
> more self-explanatory could be found.

Sure. I'm very open here. I think the selection of "." as separator was
not good. We can change that any time. But the real issue for me is, does
this make sense independend of syntax?

I still think that this is, for the most part, an implementation of
static typing. It may just be me, but I very rarely use to_str,
to_int, etc, in my code. The only time I do is when I absolutely have
to have those particular classes. Which is so uncommon for me, I can't
think of the last time I used it. But as I said, I may very well be in
the minority here.

cheers,
Mark

···

On Sat, 15 Jan 2005 05:06:13 +0900, Robert Klemme <bob.news@gmx.net> wrote:

"Curt Sampson" <cjs@cynic.net> schrieb im Newsbeitrag
news:Pine.NEB.4.61.0501241709080.14312@angelic-vtfw.cvpn.cynic.net...

···

On Fri, 14 Jan 2005, David A. Black wrote:

>> def silly_example(str.to_str, count.to_int)
>> # str and count are converted like in the example above
>> s = ""
>> count.times { s << str }
>> s
>> end
>
> obj = Object.new
> def obj.times; 10; end
> str = silly_example("hello", obj)
>
> Here you have an object that responds to 'times', so it's capable of
> being treated in a duck-typing way by simply being sent the message
> 'times' -- but if you intercept the object and do a to_int on it,
> there's trouble.
>
> (Of course you could document your method by saying that it requires
> an object that responds to to_int, but that seems a bit roundabout
> compared to just saying you want an object that responds to times.)

I don't see why there would be a need to add documentation indicating
that count must respond to times, since it's already written right there
in the code. We just need a type inference engine to find this and tell
us about it.

That would be a completely different language. I guess you're thinking of
some functional languages...

Regards

    robert

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag
news:Pine.LNX.4.61.0501140520470.15307@wobblini...

Hi --

>> [I wrote:]
>>
>> There's also the question of the interaction of this with duck

typing.

>> Of course that's always a programmer's choice, but I could imagine
>> cases where the caller would expect a duck-typing treatment and not
>> get it. For example:
>>
>> obj = Object.new
>> def obj.times; 10; end
>> str = silly_example("hello", obj)
>>
[...]
> Btw, did you purposely just return an int from your definition of

times?

> I mean, no block is invoked from that method.

I did it wrong. It should be:

   def obj.times(&block)
     10.times &block
   end

>> (Of course you could document your method by saying that it requires
>> an object that responds to to_int, but that seems a bit roundabout
>> compared to just saying you want an object that responds to times.)
>
> It's just another (supposedly shorter) form to write a common idiom.

If

> the writer of silly_example decides to do more complex treatment, he

can

> still do that. We don't loose anything. Note, that the creator of

your

> obj.times() would be similarly surprised if the implementor of
> silly_example had choosen to do it exactly like I presented in the

first

> example.
>
> I'm not sure whether I missed your point altogether. Could you please
> elaborate? Thanks!

Partly I'm just very conservative about special-case syntax and
shortcuts. I can't define exactly why, or exactly where I draw the
line, or whether there's even a line.... I think I'm also not
convinced that this (to_int etc.) is common enough or special enough
to warrant a change in method definitions semantics. I don't think I
can get much more concrete than that, so it may be that at some level
I don't have a point, rather than that you've missed it :slight_smile:

Ah, ok, I see... :slight_smile: Then let's see with what others come up. Maybe I've
orverlooked a complete showstopper and we can forget about this
immediately.

About usage of to_int et al: as these methods are fairly recent (compared
to to_i and others) I'd guess that usage is increasing and they might not
yet be as prolific as I assumed. Don't have exact numbers though.

Thanks for sharing your thoughts!

Kind regards

    robert

···

On Fri, 14 Jan 2005, Robert Klemme wrote:

Hi --

···

On Fri, 14 Jan 2005, Ilmari Heikkinen wrote:

Hi,

On 14.1.2005, at 15:31, David A. Black wrote:

def silly_example(ostr, ocount, str=ostr.to_str, count=ocount.to_int)

Yes except that then someone could call it like this:

  silly_example("hi", 1, "hello", 2)

and clobber the conversions you were doing.

Could argue that it's wanted behavior.. "if you want to hack this without hacking to_str and to_int, replace the defaulted args"

Since this IMHO is pretty much an auto-documented wish for the caller to supply objects that act like ducks.

You asked whether you could already do what Robert was proposing, by
using the construct you've suggested -- to which the answer is no,
since he his proposal didn't include that kind of overriding :slight_smile:

David

--
David A. Black
dblack@wobblini.net

"itsme213" <itsme213@hotmail.com> schrieb im Newsbeitrag news:ORTFd.3354$Ta2.397@fe2.texas.rr.com...

> silly_example will not have other access to x, y
> (*: since you did: str=str.to_str; count=count.to_int)

Wrong, because to_str need not create a new instance:

The fact that String#to_str returns self, and Fixnum.to_int returns self, is
purely coincidental aliasing (from inside your method body). The original
parm-list variables might as well be anonymous.

But it's aliasing nevertheless and thus the caller can't rely on that the instances he provides remain unchanged thinking that the body of the method never gets access to them. In fact, the aliasing might even be desired as object creations are rather expensive and people are likely to provide String instances where #to_str is needed.

Of course you can view "original arguments" as anonymous but what difference would that make?

I don't seem to get your point with this. Can you attempt another explanation?

kind regards

    robert

···

"Robert Klemme" <bob.news@gmx.net> wrote

itsme213 wrote:

Florian Gross' Binding.of_caller could probably be used to prototype ideas
like this, but it would take someone considerably smarter than me (Florian?)
to explore this :slight_smile:

I fear I'm not smart enough to understand all this pattern matching stuff just yet. But I'd certainly be willing to help out with getting Binding.of_caller to work.

"Mark Hubbart" <discordantus@gmail.com> schrieb im Newsbeitrag news:de63abca05011415224d4c29a1@mail.gmail.com...

Hi,

I think I probably was somewhat unclear in my other post. I wasn't
arguing for or against your idea (for the most part), I was going off
it and thinking up a related idea... I guess it was actually pretty
off topic.

Ah, ok, I see much clearer now. Thanks for clarifying.

"Mark Hubbart" <discordantus@gmail.com> schrieb im Newsbeitrag
news:de63abca0501141100154206a8@mail.gmail.com...

> I do this to make sure I'm allowing for maximum flexibility, or when
> working with other's code, to find out what the actual requirements
> are :slight_smile:

Well, then you'll learn that your instance must implement to_int. Same as
if someone had coded that directly in the method. I don't see this as an
argument against my suggested shortcut syntax, because that mainly affects
the *writer* of a method - not the *caller*.

My only argument against the shortcut syntax is that I can't see how
often it could be used, except to simulate static typing. I suspect
that adding a feature like this would encourage the use of static
typing in methods.

Ok, then we need a poll. Or we should dig into Ruby's std lib to see how often these methods are called.

In your example method, you called #to_int on an object that you were
just going to call #times on. This doesn't guarantee that you will get
an integer,

Of course.

and makes it difficult for others to use duck typing in
code that interfaces with yours.

The same holds true if the idiom is used inside the method body.

In fact, if they need the
functionality, then the have to resort to some hack like this:

obj = ObjectThatImplementsTimes.new
wrapper = Object.new
class << wrapper;self;end.__send__(:define_method, :to_int){obj}

A very ugly hack, just to re-allow duck typing.

The invocation of to_int is already and application of duck typing.

<snip/>

> Second, I'm not sure about the syntax. It would work
> (it currently give a parse error), but I think something better and
> more self-explanatory could be found.

Sure. I'm very open here. I think the selection of "." as separator was
not good. We can change that any time. But the real issue for me is, does
this make sense independend of syntax?

I still think that this is, for the most part, an implementation of
static typing. It may just be me, but I very rarely use to_str,
to_int, etc, in my code. The only time I do is when I absolutely have
to have those particular classes. Which is so uncommon for me, I can't
think of the last time I used it. But as I said, I may very well be in
the minority here.

We need figures here. If I find the time this weekend I'll try to come up with statistics.

    robert

···

On Sat, 15 Jan 2005 05:06:13 +0900, Robert Klemme <bob.news@gmx.net> > wrote:

Hi --

About usage of to_int et al: as these methods are fairly recent (compared
to to_i and others) I'd guess that usage is increasing and they might not
yet be as prolific as I assumed. Don't have exact numbers though.

I thought that their main purpose was to be defined on objects that
were expected to have to serve as strings or ints, etc. -- this kind
of thing:

   obj = Object.new
   def obj.to_str; "def"; end

   def another_example(str)
     "abc" << str
   end

   p another_example(obj) # "abcdef"

as opposed to being called explicitly, for which to_s and to_i would
serve more often. (Not that to_??? can't be called explicitly, of
course.)

David

···

On Fri, 14 Jan 2005, Robert Klemme wrote:

--
David A. Black
dblack@wobblini.net

>> > silly_example will not have other access to x, y
>> > (*: since you did: str=str.to_str; count=count.to_int)
>>
>> Wrong, because to_str need not create a new instance:
>
> The fact that String#to_str returns self, and Fixnum.to_int returns

self,

> is
> purely coincidental aliasing (from inside your method body). The

original

> parm-list variables might as well be anonymous.

But it's aliasing nevertheless and thus the caller can't rely on that the
instances he provides remain unchanged thinking that the body of the

method

never gets access to them. In fact, the aliasing might even be desired as
object creations are rather expensive and people are likely to provide
String instances where #to_str is needed.

Of course you can view "original arguments" as anonymous but what

difference

would that make?

I don't seem to get your point with this. Can you attempt another
explanation?

Thank you. I may have stated too strongly, and you may have read more into
it. It's not a central part of your scheme (or my generalization). Here is
my re-explanation:

First, let's limit the scope: In any object graph just about any object can
be accessible from anywhere (via transitive returns from other methods,
aliasing, globals, and constants like ObjectSpace). So in that extreme, just
about any method can be invoked on just about any object. We are not about
address aliasing, so let's just focus on those objects that are passed back
and forth via method parameters.

For these objects, your scheme allows us to say that the method body only
has named references to things returned by methods on the object. Which
means that it will not have references to the objects themselves (unless
those methods on the objects themselves lead there, or it uses other paths
through the object graph, such as via ObjectSpace).

Any better?

···

"Robert Klemme" <bob.news@gmx.net> wrote

Looks like it uses eval, which only takes a string, so I'm not sure ... Do
you think it could implement bind_vars to do the following?

def f (arr)
    bind_vars [:x, :y, :z], arr
    [x, y, z]
end

f [1, 2, 3] #=> [1, 2, 3]

Thanks.

···

"Florian Gross" <flgr@ccan.de> wrote

But I'd certainly be willing to help out with getting
Binding.of_caller to work.

Hi --

"Mark Hubbart" <discordantus@gmail.com> schrieb im Newsbeitrag news:de63abca05011415224d4c29a1@mail.gmail.com...

My only argument against the shortcut syntax is that I can't see how
often it could be used, except to simulate static typing. I suspect
that adding a feature like this would encourage the use of static
typing in methods.

Ok, then we need a poll. Or we should dig into Ruby's std lib to see how often these methods are called.

Not very :slight_smile: For 1.8.2:

$ grep '\.to_str' `find . -name "*.rb"` | grep -v to_string | wc -l
       6
$ grep '\.to_int' `find . -name "*.rb"` | wc -l
       1

(It's around 700 for to_s and 300 for to_i.)

In fact, if they need the
functionality, then the have to resort to some hack like this:

obj = ObjectThatImplementsTimes.new
wrapper = Object.new
class << wrapper;self;end.__send__(:define_method, :to_int){obj}

A very ugly hack, just to re-allow duck typing.

The invocation of to_int is already and application of duck typing.

OK, I think I've clarified my big problem with all of this:

How would you move this call to #join to a method signature?

    def meth(a)
      puts a.join(", ")
    end

I think there are only two ways:

   1. put the whole thing, including the ", ", into the signature
      (which I doubt anyone would advocate);
   2. back away from duck typing and rely on something else, probably
      #respond_to? You're then dealing with the capabilities of the
      object at one level of remove -- which, of course, is something
      one often does, but it's only a subset of available techniques
      for dealing with type and object capability. (My position is
      that duck-typing - #respond_to? > 0)

In other words, I question whether it's possible to re-model runtime
message-sending as a method signature, without some kind of major
reconception of the whole thing and/or up-front decision to drop
one or more programming techniques.

David

···

On Sat, 15 Jan 2005, Robert Klemme wrote:

--
David A. Black
dblack@wobblini.net

"itsme213" <itsme213@hotmail.com> schrieb im Newsbeitrag news:A5WFd.4845$Z%.29@fe1.texas.rr.com...

>> > silly_example will not have other access to x, y
>> > (*: since you did: str=str.to_str; count=count.to_int)
>>
>> Wrong, because to_str need not create a new instance:
>
> The fact that String#to_str returns self, and Fixnum.to_int returns

self,

> is
> purely coincidental aliasing (from inside your method body). The

original

> parm-list variables might as well be anonymous.

But it's aliasing nevertheless and thus the caller can't rely on that the
instances he provides remain unchanged thinking that the body of the

method

never gets access to them. In fact, the aliasing might even be desired as
object creations are rather expensive and people are likely to provide
String instances where #to_str is needed.

Of course you can view "original arguments" as anonymous but what

difference

would that make?

I don't seem to get your point with this. Can you attempt another
explanation?

Thank you. I may have stated too strongly, and you may have read more into
it.

Yeah, that's likely.

It's not a central part of your scheme (or my generalization). Here is
my re-explanation:

First, let's limit the scope: In any object graph just about any object can
be accessible from anywhere (via transitive returns from other methods,
aliasing, globals, and constants like ObjectSpace). So in that extreme, just
about any method can be invoked on just about any object. We are not about
address aliasing, so let's just focus on those objects that are passed back
and forth via method parameters.

For these objects, your scheme allows us to say that the method body only
has named references to things returned by methods on the object. Which
means that it will not have references to the objects themselves (unless
those methods on the objects themselves lead there, or it uses other paths
through the object graph, such as via ObjectSpace).

Any better?

Definitely! But IMHO that weakened the property so much that I ask myself whether it's still useful. :slight_smile:

Cheers

    robert

···

"Robert Klemme" <bob.news@gmx.net> wrote

itsme213 wrote:

Looks like it uses eval, which only takes a string, so I'm not sure ... Do
you think it could implement bind_vars to do the following?

def f (arr)
    bind_vars [:x, :y, :z], arr
    [x, y, z]
end

Mostly. But you would need to initialize the variables x, y and z to nil so that Ruby actually sees them as variables and not method calls.

It would work like this:

def bind_vars(names, values)
   Binding.of_caller do |context|
     setter = eval("lambda { |#{names.join(", ")}| }", context)
     setter.call(*values)
   end
end

But you need no advocating to do, even today:
    def meth (a, b = a.join(","))
        b
    end

The only difference that 'b' is a variable with a default binding, which the
caller can replace.

True?

···

"David A. Black" <dblack@wobblini.net> wrote

How would you move this call to #join to a method signature?

    def meth(a)
      puts a.join(", ")
    end

I think there are only two ways:

   1. put the whole thing, including the ", ", into the signature
      (which I doubt anyone would advocate);

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag news:Pine.LNX.4.61.0501150344320.20765@wobblini...

Hi --

"Mark Hubbart" <discordantus@gmail.com> schrieb im Newsbeitrag news:de63abca05011415224d4c29a1@mail.gmail.com...

My only argument against the shortcut syntax is that I can't see how
often it could be used, except to simulate static typing. I suspect
that adding a feature like this would encourage the use of static
typing in methods.

Ok, then we need a poll. Or we should dig into Ruby's std lib to see how often these methods are called.

Not very :slight_smile: For 1.8.2:

$ grep '\.to_str' `find . -name "*.rb"` | grep -v to_string | wc -l
      6
$ grep '\.to_int' `find . -name "*.rb"` | wc -l
      1

(It's around 700 for to_s and 300 for to_i.)

Here's my stat of ruby 1.8.2:

$ ruby -e 'Dir["**/*.{h,cC,rb,rw}"].inject(Hash.new(0)){|h,f| File.open(f){|io| io.each{|li| li.scan(/to_\w+/){|m|h[m]+=1}} };h}.sort.each{|k,v| print k," ",v,"\n"}'
to_a 193
to_above 2
to_access_path 1
to_addr 3
to_addrs 8
to_ajd 13
to_all 2
to_amjd 2
to_append 2
to_arry 5
to_ary 26
to_asn1integer 1
to_backslash 3
to_backslash_sequence 11
to_be_linked 1
to_below 2
to_bitmap 5
to_bn 1
to_bold 4
to_built_in_class 1
to_cache 4
to_check 5
to_civil 8
to_clean_up 6
to_clone 2
to_closest 2
to_commercial 4
to_consume 2
to_coords 2
to_d 6
to_date 2
to_day_fraction 3
to_dbl 2
to_dc_date 2
to_default 6
to_del 6
to_delete 2
to_der 51
to_der_if_possible 1
to_diff 3
to_digits 1
to_dir 4
to_directory_uri 2
to_e 2
to_enc 15
to_enclosed 2
to_euc_jp_from_iso_2022_jp 1
to_euc_jp_from_shift_jis 1
to_euc_jp_from_utf_8 1
to_eval 34
to_external 2
to_f 88
to_file 7
to_filename 5
to_find 3
to_flow 8
to_h 3
to_hash 21
to_hash_kv 8
to_html 5
to_i 541
to_ico 1
to_id 10
to_idx 2
to_indent_mode 4
to_index 4
to_int 3
to_internal 3
to_inum 2
to_io 10
to_iso_2022_jp_from_euc_jp 1
to_iso_8859_15 1
to_iso_8859_1_from_utf_8 1
to_jd 24
to_key 7
to_key_and_deref 1
to_label 2
to_latex 1
to_ld 2
to_level 6
to_line 1
to_lines 4
to_list 8
to_load 13
to_mailtext 3
to_mediator 12
to_mjd 2
to_name 6
to_new_year 2
to_newline 3
to_num 1
to_obj 26
to_oldpath 2
to_one 1
to_ordinal 5
to_overlapping 2
to_path 7
to_pem 9
to_pixel 6
to_png 3
to_pointer 5
to_proc 23
to_ptr 6
to_r 31
to_re 2
to_replace 4
to_rfc822text 1
to_rjd 1
to_router 5
to_rss 59
to_run 8
to_s 1379
to_s_09 1
to_s_10 1
to_s_20 1
to_s__ 2
to_s_table 2
to_s_with_iv 1
to_s_without_iv 1
to_search 2
to_set 9
to_shell 3
to_shift_jis_from_euc_jp 1
to_shift_jis_from_utf_8 1
to_src 2
to_str 32
to_string 27
to_sym 5
to_table 5
to_taskbar 2
to_text 7
to_time 9
to_time_t 1
to_uri 1
to_utc 4
to_utf 8
to_utf_8_from_euc_jp 1
to_utf_8_from_iso_8859_1 1
to_utf_8_from_shift_jis 1
to_version 5
to_wday 2
to_withtag 2
to_xml 4
to_xpath_helper 3
to_yaml 75
to_yaml_fold 3
to_yaml_properties 13
to_yaml_type 21

Sum 3143

Top counts

1379 to_s
541 to_i
193 to_a
88 to_f
75 to_yaml
59 to_rss
51 to_der
34 to_eval
32 to_str
31 to_r
27 to_string
26 to_ary
26 to_obj
24 to_jd
23 to_proc
21 to_hash
21 to_yaml_type

Kind regards

    robert

···

On Sat, 15 Jan 2005, Robert Klemme wrote:

The property is not central to either proposal, imo. I'm interested in what
you think of the generalization.

Thanks!

···

"Robert Klemme" <bob.news@gmx.net> wrote

> Any better?

Definitely! But IMHO that weakened the property so much that I ask myself
whether it's still useful. :slight_smile:

Hi --

···

On Sat, 15 Jan 2005, itsme213 wrote:

"David A. Black" <dblack@wobblini.net> wrote

How would you move this call to #join to a method signature?

    def meth(a)
      puts a.join(", ")
    end

I think there are only two ways:

   1. put the whole thing, including the ", ", into the signature
      (which I doubt anyone would advocate);

But you need no advocating to do, even today:
   def meth (a, b = a.join(","))
       b
   end

The only difference that 'b' is a variable with a default binding, which the
caller can replace.

True?

Yes -- a big difference, in my view. Mainly I meant that there's is,
I think, probably not a lot of advocacy of putting arbitrarily much of
a method into its signature. (Maybe I'm just old-fashioned though :slight_smile:

David

--
David A. Black
dblack@wobblini.net

I am curious why you think this. After all, anytime I have:
    private_obj = ...
    x = ...
    y = ...
    f x, y

By not passing my 'private_obj' into #f, and based on how f is supposed to
behave, I certainly have some confidence that calling #f(x,y) will not
unexpectedly mess around with private_obj. But, as you pointed out, due to
aliasing via x & y methods called inside #f (as well as other paths through
the object graph) there is no real guarantee of this, other than what I know
about the promised behaior of #f, and my x and y objects.

Despite this, don't you think we rely on such confidence all the time ? :slight_smile:

···

"Robert Klemme" <bob.news@gmx.net> wrote

Definitely! But IMHO that weakened the property so much that I ask myself
whether it's still useful. :slight_smile:

Hi --

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag news:Pine.LNX.4.61.0501150344320.20765@wobblini...

Hi --

"Mark Hubbart" <discordantus@gmail.com> schrieb im Newsbeitrag news:de63abca05011415224d4c29a1@mail.gmail.com...

My only argument against the shortcut syntax is that I can't see how
often it could be used, except to simulate static typing. I suspect
that adding a feature like this would encourage the use of static
typing in methods.

Ok, then we need a poll. Or we should dig into Ruby's std lib to see how often these methods are called.

Not very :slight_smile: For 1.8.2:

$ grep '\.to_str' `find . -name "*.rb"` | grep -v to_string | wc -l
      6
$ grep '\.to_int' `find . -name "*.rb"` | wc -l
      1

(It's around 700 for to_s and 300 for to_i.)

Here's my stat of ruby 1.8.2:

$ ruby -e 'Dir["**/*.{h,cC,rb,rw}"].inject(Hash.new(0)){|h,f| File.open(f){|io| io.each{|li| li.scan(/to_\w+/){|m|h[m]+=1}} };h}.sort.each{|k,v| print k," ",v,"\n"}'
to_a 193
to_above 2
to_access_path 1
to_addr 3

[...]

I would tend to want to match /\.to_\w+/, though I guess some things
have embedded to's (like pixel_to_coords). Also, some of the ones
you've found are in comments, such as secs_to_new_year, which is given
in the documentation as an example of something one might write with
DateTime, so it really doesn't have much in common with to_str or
to_int at the language level.

(I do love grepping the lib, I must admit :slight_smile:

David

···

On Mon, 17 Jan 2005, Robert Klemme wrote:

On Sat, 15 Jan 2005, Robert Klemme wrote:

--
David A. Black
dblack@wobblini.net