www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - std.digest: can we get rid of start() functions?

reply Piotr Szturmaj <bncrbme jadamspam.pl> writes:
And replace them with global reset function:

void reset(T)(ref T digest)
     if (isDigest!T)
{
     digest = T.init;
}

Current usage:

SHA1 sha1;
sha1.start();
... calculate hash
sha1.start(); // start again
... calculate hash

New usage:

SHA1 sha1;
... calculate hash
sha1.reset(); // start egain
... calculate hash
Oct 10 2012
next sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Wed, 10 Oct 2012 12:55:59 +0200
schrieb Piotr Szturmaj <bncrbme jadamspam.pl>:

 And replace them with global reset function:
 
 void reset(T)(ref T digest)
      if (isDigest!T)
 {
      digest = T.init;
 }
 
 Current usage:
 
 SHA1 sha1;
 sha1.start();
 ... calculate hash
 sha1.start(); // start again
 ... calculate hash
 
 New usage:
 
 SHA1 sha1;
 ... calculate hash
 sha1.reset(); // start egain
 ... calculate hash

Unlike classes, structs don't mandate a ctor call, so in general you need to disguise the constructor as 'start()' 'Create()' or similar, where T.init is not sufficient. If on the other hand, you use a ".isInitialized = false" field instead of start(), then you'd have to unnecessarily check that every time data is added to the digest, instead of doing it once. (That might be personal taste though :) ) I think the constraints are: * no start() method ever takes arguments * no digest needs to allocate to start * no digest depends on global/static variables -- Marco
Oct 10 2012
next sibling parent Piotr Szturmaj <bncrbme jadamspam.pl> writes:
Marco Leise wrote:
 Unlike classes, structs don't mandate a ctor call, so in
 general you need to disguise the constructor as 'start()'
 'Create()' or similar, where T.init is not sufficient.

I know, but in case of digests their init data is always known at compile time, hence no special "constructor" is needed.
 I think the constraints are:
 * no start() method ever takes arguments
 * no digest needs to allocate to start
 * no digest depends on global/static variables

Yes, these constraints do not prevent digest structs to be correctly initialized after declaration.
Oct 10 2012
prev sibling parent Piotr Szturmaj <bncrbme jadamspam.pl> writes:
H. S. Teoh wrote:
 Then you could just write:

 	SHA1 sha1;
 	// calculate hash
 	sha1 = SHA1.init;
 	// calculate hash
 	...

In my proposal reset() does exactly the same.
Oct 10 2012
prev sibling next sibling parent Johannes Pfau <nospam example.com> writes:
Am Wed, 10 Oct 2012 15:02:40 +0200
schrieb Marco Leise <Marco.Leise gmx.de>:

 Am Wed, 10 Oct 2012 12:55:59 +0200
 schrieb Piotr Szturmaj <bncrbme jadamspam.pl>:
 
 And replace them with global reset function:
 
 void reset(T)(ref T digest)
      if (isDigest!T)
 {
      digest = T.init;
 }
 
 Current usage:
 
 SHA1 sha1;
 sha1.start();
 ... calculate hash
 sha1.start(); // start again
 ... calculate hash
 


There's makeDigest which calls start for you, so you can write code like this: auto sha1 = makeDigest!SHA1(); //calculate hash sha1.start(); //start again //calculate hash... But the digests still have to implement a start method, even if it's only a "this = typeof(this).init;". Maybe we could avoid the start method by introducing a fallback UFCS start method...
 Unlike classes, structs don't mandate a ctor call, so in
 general you need to disguise the constructor as 'start()'
 'Create()' or similar, where T.init is not sufficient. If on
 the other hand, you use a ".isInitialized = false" field
 instead of start(), then you'd have to unnecessarily check
 that every time data is added to the digest, instead of doing
 it once. (That might be personal taste though :) )
 
 I think the constraints are:
 * no start() method ever takes arguments
 * no digest needs to allocate to start
 * no digest depends on global/static variables
 

Yes, that's the main reason why we have 'start', but it also must work as a reset function. The difficult question is whether there actually is a hash algorithm (or whether there will be one in the future) which needs such a complex start method. No-allocation often means no C wrapper (although a C API could allow to use stack objects, but often they just provide opaque structs), so this is a little controversial. But if we allowed allocation we'd have to worry about deallocation as well and then things get tricky. Reference counting is probably still the easiest solution for those cases.
Oct 10 2012
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Wed, 10 Oct 2012 16:28:36 +0200
schrieb Johannes Pfau <nospam example.com>:

 There's makeDigest which calls start for you, so you can write code
 like this:
 
 auto sha1 = makeDigest!SHA1();
 //calculate hash
 sha1.start(); //start again
 //calculate hash...

Just this point, I think it adds mental bloat. It is still easier to remember and shorter to use: SHA1 sha1; sha1.start(); //calculate hash sha1.start(); //calculate hash... -- Marco
Oct 10 2012
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 10, 2012 at 05:16:38PM +0200, Marco Leise wrote:
 Am Wed, 10 Oct 2012 16:28:36 +0200
 schrieb Johannes Pfau <nospam example.com>:
 
 There's makeDigest which calls start for you, so you can write code
 like this:
 
 auto sha1 = makeDigest!SHA1();
 //calculate hash
 sha1.start(); //start again
 //calculate hash...

Just this point, I think it adds mental bloat. It is still easier to remember and shorter to use: SHA1 sha1; sha1.start(); //calculate hash sha1.start(); //calculate hash...

What makes it so difficult that we cannot do this: struct MyHash { bool is_init = false; ... void init() { ... is_init = true; } void computeHash(...) { if (!is_init) init(); // Continue as usual ... } } Then you could just write: SHA1 sha1; // calculate hash sha1 = SHA1.init; // calculate hash ... Fits in better with the language, and no need to remember to call start(), which adds mental load 'cos you have to remember it's called "start" and not something else, and it's also is error-prone 'cos people will forget to do it. T -- Famous last words: I wonder what will happen if I do *this*...
Oct 10 2012
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Oct 10, 2012 at 06:21:10PM +0200, Piotr Szturmaj wrote:
 H. S. Teoh wrote:
Then you could just write:

	SHA1 sha1;
	// calculate hash
	sha1 = SHA1.init;
	// calculate hash
	...

In my proposal reset() does exactly the same.

My point was that there's no need to remember that there's a method called "start" or "reset", etc., when we can just use .init which is common to all types in D. It reduces cognitive load. T -- EMACS = Extremely Massive And Cumbersome System
Oct 10 2012