What about a set hash_keeporder on/off

326 views
Skip to first unread message

Lorenzo Fiorini

unread,
Feb 9, 2013, 4:45:18 AM2/9/13
to harbou...@googlegroups.com
I've followed the discussion about hash order but I wonder if it could
be possible to create sth like:

set hash_keeporder on/off

A set on/off would allow to choose between order and performance.

Hashes are a key feature in REST/JSON programming and hb_hkeeporder is
not a solution since it doesn't change the order of the nested hashes.

f.e.

local hData := {=>}
hb_hkeeporder( hData, true )
hData := { "request" => { "cRequest" => _REQUEST:cRequest, ;
"cReqMethod" => _REQUEST:cReqMethod } ;
} ;
}

doesn't mean that the nested "request" hash is ordered you need to write:

local hData := {=>}
local hRequest := {=>}
hb_hkeeporder( hData, true )
hb_hkeeporder( hRequest, true )

hRequest[ "cRequest" ] := _REQUEST:cRequest
hRequest[ "cReqMethod" ] := _REQUEST:cReqMethod

hData[ "Request" ] := hRequest

Any comment?

best regards,
Lorenzo

Przemyslaw Czerpak

unread,
Feb 9, 2013, 7:11:09 AM2/9/13
to harbou...@googlegroups.com
On Sat, 09 Feb 2013, Lorenzo Fiorini wrote:

Hi,

> I've followed the discussion about hash order but I wonder if it could
> be possible to create sth like:
>
> set hash_keeporder on/off
>
> A set on/off would allow to choose between order and performance.
>
> Hashes are a key feature in REST/JSON programming and hb_hkeeporder is
> not a solution since it doesn't change the order of the nested hashes.

I'm strongly against new SET because it only creates problems for
programmers which have to create code ready to work in all cases.
Anyhow I agree that it's a problem in many cases that literal hashes
are resorted by HVM. I also created JSON RPC client/server/peer library
and it's real problem when I'm creating new messages because I cannot
use literal hashes if I'm not sure that receiver supports position
independent names parameters.

I think that it's time to change a little bit hash engine and set
that order is kept by default. In fact with some cost of additional
memory it also increases the speed because new hash array has to be
resorted.
Maybe I'll add also support for attributes in hash arrays.
For my own use I have two simple functions: hashToXml() and XmlToHash()
When the same key is repeated then XmlToHash() changes the value to
array. It's very simple and efficient solution IMO much better then
different XML libraries but it has one problem. I cannot control
XML node attributes in hashToXml() so sometimes I cannot use it.
Optional support for attributes in hash arrays can nicely resolve
this problem.
I'll try to commit such modifications in this month.

best regards,
Przemek

Lorenzo Fiorini

unread,
Feb 9, 2013, 10:14:26 AM2/9/13
to harbou...@googlegroups.com
On Sat, Feb 9, 2013 at 1:11 PM, Przemyslaw Czerpak
<dru...@poczta.onet.pl> wrote:

> Anyhow I agree that it's a problem in many cases that literal hashes
> ...
> Optional support for attributes in hash arrays can nicely resolve
> this problem.
> I'll try to commit such modifications in this month.

Many thanks.

best regards,
Lorenzo

Antonio Carlos

unread,
Feb 9, 2013, 3:26:08 PM2/9/13
to harbou...@googlegroups.com
>>For my own use I have two simple functions: hashToXml() and
XmlToHash()
>>When the same key is repeated then XmlToHash() changes the value
to
>>array. It's very simple and efficient solution IMO much better
then
>>different XML libraries but it has one problem. I cannot
control
>>XML node attributes in hashToXml() so sometimes I cannot use
it.
>>Optional support for attributes in hash arrays can nicely
resolve
>>this problem.
>>I'll try to commit such modifications in this month.

Hi Przemek.

First, thanks for your job.

Second: Do you have intentions to share hashToXml() and xmlToHash() please
?

Regards,

Toninho.

Bacco

unread,
Feb 11, 2013, 9:55:19 AM2/11/13
to harbou...@googlegroups.com
"I think that it's time to change a little bit hash engine and set
that order is kept by default."

I'm waiting for this for months :)
Happy to hear it.

Regards,
Bacco
> --
> You received this message because you are subscribed to the Google Groups
> "Harbour Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to harbour-deve...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
>

Przemyslaw Czerpak

unread,
Feb 11, 2013, 1:08:00 PM2/11/13
to harbou...@googlegroups.com
On Sat, 09 Feb 2013, Antonio Carlos wrote:

Hi,

> Hi Przemek.
> First, thanks for your job.
> Second: Do you have intentions to share hashToXml() and xmlToHash() please

I see in my mail box that few people asked about it.
I'm attaching the code.
As I said it's very simple without support for attributes though
in many cases it's enough.
Please also note that you can store all basic types in hash array
and then convert it to XML string but when hash array is decoded
from the XML string then all values are read as strings so if you
expect different types then you should make conversion from strings.
This version for decoding XML data uses minixml library.

Attached prg contains simple test code in main() function.
As you can see the order in literal hash is changed by current HVM.

best regards,
Przemek
h2xml.prg

DB Topas

unread,
Feb 11, 2013, 1:19:41 PM2/11/13
to harbou...@googlegroups.com
Hi,


AFAIR, some of my code (commited 2012-01-27 18:25) depends on
keeporder=F. It is hb_hashScanSoft( pHash, pKey, &nPos ) and extension
of HB_HHASKEY( aHash, xKey [, @nPos ] ). These enables to use hash as
binary sort arrays, but I used it only once in my code, and I doubt
anyone else uses these extensions. If you find it contradicts to some
idea of hash, feel free to remove it. Binary search is a good thing, but
maybe it should be implemented in a different way.

Actually, I would even support the idea of completely removing
keeporder=F hash mode. Using keeporder=T describes precise order of hash
enumeration. Current undefined order creates misunderstanding for some
developers.


Regards,
Mindaugas

Przemyslaw Czerpak

unread,
Feb 11, 2013, 2:07:48 PM2/11/13
to harbou...@googlegroups.com
On Mon, 11 Feb 2013, DB Topas wrote:

Hi,

> AFAIR, some of my code (commited 2012-01-27 18:25) depends on
> keeporder=F. It is hb_hashScanSoft( pHash, pKey, &nPos ) and
> extension of HB_HHASKEY( aHash, xKey [, @nPos ] ). These enables to
> use hash as binary sort arrays, but I used it only once in my code,
> and I doubt anyone else uses these extensions. If you find it
> contradicts to some idea of hash, feel free to remove it. Binary
> search is a good thing, but maybe it should be implemented in a
> different way.

I remember it.
Anyhow if you define base hash array keeping the order:
{ 10=>, 20=>, 30=>, 40=>, 50=>, 60=>, 70=>, 80=>, 90=> }
then it will still work.
We can also create new function which will resort hash array
so they can still be used to define ranges.

> Actually, I would even support the idea of completely removing
> keeporder=F hash mode. Using keeporder=T describes precise order of
> hash enumeration. Current undefined order creates misunderstanding
> for some developers.

I also think that keeping the order may resolve many user problems
and questions. For sure it clearly defines FOR EACH order though
there is a question about hb_hDel() behavior. The faster version
which reduces memory move cost breaks the order so maybe the keeporder
flag should be used only inside hb_hDel() and when is not set we can
use faster version which moves the last element into the place freed
by deleted one.
For sure hb_hashResort() should be updated because with keeporder set
as default it will make much more often full sorting instead of "order
correction".

best regards,
Przemek

Pritpal Bedi

unread,
Feb 11, 2013, 2:48:17 PM2/11/13
to harbou...@googlegroups.com
Thanks Przemek


I see in my mail box that few people asked about it.
I'm attaching the code.


I was one of them.


Pritpal Bedi 

Antonio Carlos

unread,
Feb 11, 2013, 6:08:07 PM2/11/13
to harbou...@googlegroups.com
>>I'm attaching the code.
Thank you.
Regards.

vszakats

unread,
Feb 14, 2013, 8:09:15 PM2/14/13
to harbou...@googlegroups.com
Related to this, I've extended HB_HGETDEF() function to 
support hash/array combinations and multiple indexes as well:
    hb_HGetDef_2( <hHash|aArray>, <xIndex>|<aIndex>, [<xDefault>] ) -> <xValue>

It's useful to pull items from a JSON/XML-like memory variable:
   LOCAL d := { "A" => { { "B" => "1b", "C" => "1c" }, { "C" => "2c", "B" => "2b" } } }
   ? hb_HGetDef_2( d, { "A", 2, "B" }, "*" )

I'm unsure about some things about it, f.e. the name 
(it accepts pure arrays as well, even though it's logical 
extension of HB_HGETDEF()), and the way multiple 
indexes are passed, I don't love the array of indexes, 
but any other solution felt problematic for one reason 
or another. It may even have bugs, or may not be fully 
optimal code.

Input is welcome.

BTW this function might also have a pair to set an 
arbitrary element in a complex JSON/XML like var:
    HB_HSET( <hHash|aArray>, <xIndex|aIndex>, <xValue> )

-- Viktor
hb_hgetdef_2.zip

Przemyslaw Czerpak

unread,
Feb 15, 2013, 4:35:22 AM2/15/13
to harbou...@googlegroups.com
On Thu, 14 Feb 2013, vszakats wrote:

Hi,

> Related to this, I've extended HB_HGETDEF() function to
> support hash/array combinations and multiple indexes as well:
> hb_HGetDef_2( <hHash|aArray>, <xIndex>|<aIndex>, [<xDefault>] ) ->
> <xValue>
>
> It's useful to pull items from a JSON/XML-like memory variable:
> LOCAL d := { "A" => { { "B" => "1b", "C" => "1c" }, { "C" => "2c", "B"
> => "2b" } } }
> ? hb_HGetDef_2( d, { "A", 2, "B" }, "*" )

begin sequence with {||break()}
? d[ "A", 2, "B" ]
recover
? "*"
end sequence

> I'm unsure about some things about it, f.e. the name
> (it accepts pure arrays as well, even though it's logical
> extension of HB_HGETDEF()), and the way multiple
> indexes are passed, I don't love the array of indexes,
> but any other solution felt problematic for one reason
> or another. It may even have bugs, or may not be fully
> optimal code.
> Input is welcome.

function my_HGet( hVal, xDefault, ... )
local xResult
begin sequence with {||break()}
xResult := hVal[ ... ]
recover
xResult := xDefault
end sequence
return xResult


> BTW this function might also have a pair to set an
> arbitrary element in a complex JSON/XML like var:
> HB_HSET( <hHash|aArray>, <xIndex|aIndex>, <xValue> )

function my_HSet( hVal, xValue, ... )
local xResult
begin sequence with {||break()}
hVal[ ... ] := xValue
xResult := .t.
recover
xResult := .f.
end sequence
return xResult

As you can see such code can be quite easy created by user.
If you want to use array as indexes then it's enough to
replace ... with aIndex and then use hb_arrayToParams( aIndex ).
Anyhow we can extend HB_HGET*()/HB_G_SET() functions to accept
arrays as set of indexes or create separate functions for it
just like above ones which will operate on arrays.

best regards,
Przemek

vszakats

unread,
Feb 15, 2013, 4:49:52 AM2/15/13
to harbou...@googlegroups.com
Hi Przemek,

Thanks for the input.
 
      begin sequence with {||break()}
         ? d[ "A", 2, "B" ]
      recover
         ? "*"
      end sequence

I know, but above seems quite slow if I wrap it in a function, 
if I wrap each line (say 100) like above, the above construct 
makes code looking extremely ugly (and also slow/big). So 
what I'm saying is not that it was impossible to solve so far, 
but when working with lots of variables, it will make coding 
smoother.

Similar to HB_HGETDEF(), which could always be replaced 
by 2 times slower an 5 more line long construct:

   IF "key" $ hash
      ? hash[ key ]
   ELSE
      ? "*"
   ENDIF

   function my_HGet( hVal, xDefault, ... )
      local xResult
      begin sequence with {||break()}
         xResult := hVal[ ... ]
      recover
         xResult := xDefault
      end sequence
   return xResult

BTW, this was the first syntax I was experimenting with.

Can you guesstimate how performance of above can 
compare to my solution?
 
> BTW this function might also have a pair to set an
> arbitrary element in a complex JSON/XML like var:
>     HB_HSET( <hHash|aArray>, <xIndex|aIndex>, <xValue> )

   function my_HSet( hVal, xValue, ... )
      local xResult
      begin sequence with {||break()}
         hVal[ ... ] := xValue
         xResult := .t.
      recover
         xResult := .f.
      end sequence
   return xResult

As you can see such code can be quite easy created by user.
If you want to use array as indexes then it's enough to
replace ... with aIndex and then use hb_arrayToParams( aIndex ).
Anyhow we can extend HB_HGET*()/HB_G_SET() functions to accept
arrays as set of indexes or create separate functions for it
just like above ones which will operate on arrays. 

I think it'd be helpful when working with many such fields.

-- Viktor

Przemyslaw Czerpak

unread,
Feb 18, 2013, 11:03:02 AM2/18/13
to harbou...@googlegroups.com
Hi,

I'm attaching updated version which uses hb_strReplace() for
special characters and and has workaround for MiniXML which
decodes ![CDATA[ values in raw form.

best regards,
Przemek
h2xml.prg

ToninhoFWi

unread,
Feb 18, 2013, 11:07:00 AM2/18/13
to harbou...@googlegroups.com
Thank you.



-----Mensagem Original-----
From: Przemyslaw Czerpak
Sent: Monday, February 18, 2013 1:03 PM
To: harbou...@googlegroups.com
Subject: Re: [harbour] What about a set hash_keeporder on/off
Reply all
Reply to author
Forward
0 new messages