[EMAIL PROTECTED]>
Mime-Version: 1.0 (Apple Message framework v619)
Content-Type: text/plain; charset=US-ASCII; format=flowed
Message-Id: <[EMAIL PROTECTED]>
Content-Transfer-Encoding: 7bit
Cc: Rob Kinyon <[EMAIL PROTECTED]>
From: Stevan Little <[EMAIL PROTECTED]>
Subject: Re: [sw-design] Commands::Guarded
Date: Tue, 23 Nov 2004 14:52:00 -0500
To: practical discussion of Perl software design <[EMAIL PROTECTED]>
X-Mailer: Apple Mail (2.619)

Rob,

On Nov 23, 2004, at 2:33 PM, Rob Kinyon wrote:
> Stevan -
>
>     If I understand you correctly, the main difference between
> preconditions and ensures are the way they are handled if they fail.
>
> If a precondition fails, raise an exception.
> If an ensure block fails the first time, run the using block.

And if it passes though, it will skip running the block.

> If an ensure block fails the second time, raise an exception.
>

I see all your points, there are ways to get around it, but I still 
think it would be nice to have a pure pre-condition block which is only 
concerned with the "before" of the block and has no need to deal with 
the "after". Your example of the file is simple enough, but I would 
think that getting any more complex than that would get difficult to 
read. At least in my mind it makes more sense to check a positive 
condition before, then check the negatives as either invariants/failure 
conditions.

        If something is true, do something. If something is not true now, then 
we failed.

I don't know, it's just how my mind works.

Steve




> In the case of deleting a file, that's the perfect situation for an
> ensure/using pair. You're attempting to make sure that a file is
> deleted. So, you're trying to ensure that, once this step is
> completed, the file doesn't exist.
>
> step DeleteFile =>
>     ensure { !-f $filename }
>     using { unlink $filename }
> ;
>
> I'm still trying to find a place where you need an assertion around a
> using block. The only thing I can think of is if you want to make sure
> you avoid catastrophic failures that are outside your control.
> Something like databases are down or NFS mounts are unavailable. But,
> I would think you'd want to attempt to reconnect, so you'd do
> something like:
>
> step MakeSureDbhConnected =>
>     ensure { $dbh->is_connected }
>     using { $dbh->reconnect( @vars ) }
> ;
>
> Or something similar for NFS mounts and other network resources.
>
> What am I missing?
>
> Rob
>
> On Tue, 23 Nov 2004 14:03:35 -0500, Stevan Little
> <[EMAIL PROTECTED]> wrote:
>> Rob,
>>
>> On Nov 23, 2004, at 12:50 PM, Rob Kinyon wrote:
>>> I'm a little confused as to why one would need pre- and
>>> post-conditions at all. The "ensure" block would seem to handle the
>>> whole thing as it is both the pre- and post-condition to the "using"
>>> block. (What about aliasing "doing" to "using"?)
>>
>> There may be preconditions which need to be true prior to running the
>> code, but which are false after the code is run. For instance, 
>> deleting
>> a file. I want to be sure its there first, then delete it, and
>> afterwards the file is gone so the pre-condition would fail.
>>
>> Also the ensure works by being false before the using block and then
>> true afterwards, so using it as a pre-condition would be difficult IMO
>> since you would have to define the negative rather than the positive.
>>
>> Steve
>>
>>
>>
>>
>>> The only thing I can see being useful is allowing for more than one
>>> "ensure" and more than one "using" block. This would allow me to 
>>> write
>>> something like:
>>>
>>> step Foo =>
>>>     ensure { -f '/net' }
>>>     ensure { -f '/net/foo' }
>>>     ensure { The actual thing I care about }
>>>     using { Do something here }
>>>     using { Do something else here}
>>> ;
>>>
>>> The benefit is that you can do things like:
>>>
>>> sub foo { blahblah }
>>> sub bar { blahblah }
>>>
>>> step Foo =>
>>>     ensure \&foo
>>>     ensure \&bar
>>>     using { Do something }
>>> ;
>>>
>>> And have reusable ensure clauses. Sure, you could do:
>>> step Foo =>
>>>     ensure { foo() && bar() }
>>>     using { Do something }
>>> ;
>>>
>>> But, there's no reason not to allow it, that I can think of. This is
>>> especially true when treating them as assertions.
>>>
>>> *thinks a little bit*
>>>
>>>>> I've been thinking about what to do if either the C<ensure> or the
>>>>> <using>
>>>>> blocks are missing.  Currently the module throws an exception, but 
>>>>> I
>>>>> don't
>>>>> think that's right.  In an earlier draft of the module, I had an
>>>>> "ALWAYS"
>>>>> variant that ran the C<using> clause whether or not the C<ensure> 
>>>>> was
>>>>> present.  Surely
>>>>>
>>>>>   step withoutUsing =>
>>>>>     ensure { -f '/boot/vmunix' }
>>>>>   ;
>>>>>
>>>>> should be treated as an assertion: if it's true, go on, if false,
>>>>> throw an
>>>>> exception.  But
>>>>>
>>>>>   step withoutEnsure =>
>>>>>     using { mkdir "/net" }
>>>>>     ;
>>>>>
>>>>> seems somewhat useless to me.  Considering the fact that other 
>>>>> blocks
>>>>> may
>>>>> exist (sanity/rollback/etc.), perhaps a missing C<ensure> should be
>>>>> treated specially so it fails before C<using> and succeeds after.
>>>>
>>>> IMO lack of them is programmer error, and should throw an exeption.
>>>> What is the use of using your framework but to use the ensure and
>>>> using
>>>> directives and get those benefits? Otherwise are you not just adding
>>>> several levels of indirection for a subroutine call?
>>>
>>> I agree that ensure should always be there. using not being there ...
>>> *shrugs* - not so big a deal.
>>>
>>>> I also have a feature suggestion for you, as this is something I
>>>> recently ran into. How about the ability to have a timeout on the
>>>> block? I recently had a problem where a cron job was hanging for 
>>>> about
>>>> 8 hours because a very odd condition occurred which caused a
>>>> subprocess
>>>> to require user input. The result was that everything seemed to 
>>>> report
>>>> success, but the process was not yet complete (and so couldn't fail
>>>> and
>>>> tell me what was wrong). Not until I checked the output of top did I
>>>> see what was wrong. No granted it was my own stupid fault (I am 
>>>> mostly
>>>> a programmer, and I am a mediocre sys-admin at best), but a timeout 
>>>> on
>>>> that particular block of code would have been nice.
>>>
>>> I like the idea of a "no_longer_than" with a prototype of ($@) that
>>> takes a number of seconds to run. Alternatively, you could use a
>>> format of /\d+[A-Za-z]?/ and allow things like 30m, 2d, 12h, 3600s,
>>> etc.
>>>
>>> ********
>>>
>>> NOTE: One thing that you need to be aware of is the potential for
>>> memory leaks and other problems using the & prototype. See
>>> http://www.perlmonks.org/?node_id=278900 for more info.
>>>
>>> ********
>>>
>>> _______________________________________________
>>> sw-design mailing list
>>> [EMAIL PROTECTED]
>>> http://metaperl.com/cgi-bin/mailman/listinfo/sw-design
>>>
>>
>>
>


_______________________________________________
sw-design mailing list
[EMAIL PROTECTED]
http://metaperl.com/cgi-bin/mailman/listinfo/sw-design

Reply via email to