Old doesn't work with object fields

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

Old doesn't work with object fields

4D Tech mailing list
The subject says it all. It's not documented.

Is there a good generic way to see if an object field has changed from within a trigger?

--
Jeffrey Kain
[hidden email]




**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
Jeff,
I think this is going to track back to a discussion some time ago about
trying to compare two c-objects, or JSON, to each other. It turns out to be
really tricky. For instance:

JSON a:  {key1:1234, key2:"abcd"}

is that equal to

{key2:"abcd", key1:1234}

or

{key2:"abcd", key1:"1234"}

 and so on.

I think, haven't tried, to test Modified on the c-obj field. That might
work for you. Otherwise I'd just update the c-obj every time.


On Wed, Feb 22, 2017 at 9:02 AM, Jeffrey Kain via 4D_Tech <
[hidden email]> wrote:

> The subject says it all. It's not documented.
>
> Is there a good generic way to see if an object field has changed from
> within a trigger?
>
> --
> Jeffrey Kain
> [hidden email]
>
>
>
>
> **********************************************************************
> 4D Internet Users Group (4D iNUG)
> FAQ:  http://lists.4d.com/faqnug.html
> Archive:  http://lists.4d.com/archives.html
> Options: http://lists.4d.com/mailman/options/4d_tech
> Unsub:  mailto:[hidden email]
> **********************************************************************




--
Kirk Brooks
San Francisco, CA
=======================
**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
Doesn't Modified only work in a form event?

So it turns out that Old works fine with an object field, but you can't do an = comparison. I think what I'm going to do is the following:

  If ((JSON Stringify($fieldPtr->))#(JSON Stringify(Old($fieldPtr->))))

Seems really inefficient, but it works.

Jeff

--
Jeffrey Kain
[hidden email]

> On Feb 22, 2017, at 12:52 PM, Kirk Brooks via 4D_Tech <[hidden email]> wrote:
>
> I think this is going to track back to a discussion some time ago about
> trying to compare two c-objects, or JSON, to each other. It turns out to be
> really tricky. For instance:
>
> JSON a:  {key1:1234, key2:"abcd"}
>
> is that equal to
>
> {key2:"abcd", key1:1234}
>
> or
>
> {key2:"abcd", key1:"1234"}
>
> and so on.
>
> I think, haven't tried, to test Modified on the c-obj field. That might
> work for you. Otherwise I'd just update the c-obj every time.

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
4D unpacks it the same each time?

> On Feb 22, 2017, at 10:03 AM, Jeffrey Kain via 4D_Tech <[hidden email]> wrote:
>
>  If ((JSON Stringify($fieldPtr->))#(JSON Stringify(Old($fieldPtr->))))
>
> Seems really inefficient, but it works.

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
Seems to...

--
Jeffrey Kain
[hidden email]

> On Feb 22, 2017, at 1:04 PM, Lee Hinde via 4D_Tech <[hidden email]> wrote:
> 4D unpacks it the same each time?

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
In reply to this post by 4D Tech mailing list
Hi Jeff,

>  If ((JSON Stringify($fieldPtr->))#(JSON Stringify(Old($fieldPtr->))))

This only works if the order of the keys in the object stays the same which may not be true depending on how you change the object. I’ve pasted in a method below that you can use to compare two objects which don’t care about the order of keys. I use it in a similar situation to what you are doing and it works well.

The method name is “OBJ_IsEqual”. It calls itself, so if you use a different name make sure you change that in the code.

Vincent de Lachaux posted the original code which I then stole. :-)

--
Cannon.Smith
Synergy Farm Solutions Inc.
Hill Spring, AB Canada
403-626-3236
<[hidden email]>
<www.synergyfarmsolutions.com>



  //Compares two objects. If they are the same (ie. they have exactly the same elements and values),
  //the method returns true. Thanks to Vincent de Lachaux for the original code which has been changed
  //slightly to more closely match my style.

C_OBJECT($1;$oFirst)
C_OBJECT($2;$oSecond)
C_BOOLEAN($0;$fIsEqual)

$oFirst:=$1
$oSecond:=$2
$fIsEqual:=False  //Default to false

C_LONGINT($x;$y;$lFirstItemCount;$lSecondItemCount;$lFirstPropertyCount;$lSecondPropertyCount)
ARRAY LONGINT($alFirstType;0)
ARRAY TEXT($atFirstProperty;0)
ARRAY LONGINT($alSecondType;0)
ARRAY TEXT($atSecondProperty;0)

OB GET PROPERTY NAMES($oFirst;$atFirstProperty;$alFirstType)
OB GET PROPERTY NAMES($oSecond;$atSecondProperty;$alSecondType)
$lFirstPropertyCount:=Size of array($atFirstProperty)
$lSecondPropertyCount:=Size of array($atSecondProperty)

If ($lFirstPropertyCount=$lSecondPropertyCount)  //They won't be equal if they have different property counts
        If ($lFirstPropertyCount>0)
                  //Sort arrays because the properties could be in a different order
                SORT ARRAY($atFirstProperty;$alFirstType)
                SORT ARRAY($atSecondProperty;$alSecondType)
               
                  //Now compare each property
                For ($x;1;$lFirstPropertyCount)
                       
                        Case of
                                : ($atFirstProperty{$x}#$atSecondProperty{$x})  //Check property name
                                        $fIsEqual:=False
                                       
                                : ($alFirstType{$x}#$alSecondType{$x})  //Check property type
                                        $fIsEqual:=False
                                       
                                : ($alFirstType{$x}=Is object)
                                          //compare the two objects
                                        $fIsEqual:=OBJ_IsEqual (\
                                        OB Get($oFirst;$atFirstProperty{$x};Is object);\
                                        OB Get($oSecond;$atFirstProperty{$x};Is object))
                                       
                                : ($alFirstType{$x}=Object array)
                                          //In an object array we can massage all the array types back into text except object themselves.
                                          //So we get two sets of arrays, one text and the other objects. Then we can deal with either kind
                                          //as we walk through each element.
                                       
                                        ARRAY OBJECT($aoFirst;0)  //Reset arrays
                                        ARRAY TEXT($atFirst;0)
                                        ARRAY OBJECT($aoSecond;0)
                                        ARRAY TEXT($atSecond;0)
                                        OB GET ARRAY($oFirst;$atFirstProperty{$x};$aoFirst)  //Get text and object types
                                        OB GET ARRAY($oFirst;$atFirstProperty{$x};$atFirst)
                                        OB GET ARRAY($oSecond;$atFirstProperty{$x};$aoSecond)
                                        OB GET ARRAY($oSecond;$atFirstProperty{$x};$atSecond)
                                       
                                        $lFirstItemCount:=Size of array($aoFirst)
                                        $lSecondItemCount:=Size of array($aoSecond)
                                        If ($lFirstItemCount=$lSecondItemCount)
                                                For ($y;1;$lFirstItemCount;1)
                                                        If ((OB Is defined($aoFirst{$y})) & (OB Is defined($aoSecond{$y})))  //If they are both objects
                                                                $fIsEqual:=OBJ_IsEqual ($aoFirst{$y};$aoSecond{$y})
                                                        Else   //Compare text
                                                                $fIsEqual:=($atFirst{$y}=$atSecond{$y})
                                                        End if
                                                        If ($fIsEqual=False)
                                                                $y:=$lFirstItemCount+1  //Abort loop
                                                        End if
                                                End for
                                        Else
                                                $fIsEqual:=False
                                        End if
                                       
                                Else   //For any other object type, we simply compare the values
                                        $fIsEqual:=(OB Get($oFirst;$atFirstProperty{$x})=OB Get($oSecond;$atFirstProperty{$x}))
                                       
                        End case
                       
                        If ($fIsEqual=False)
                                $x:=$lFirstPropertyCount+1  //Abort loop
                        End if
                       
                End for
               
        Else   //If there are not elements in either one, they are both equal
                $fIsEqual:=True
        End if
End if

$0:=$fIsEqual

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
Awesome, thanks Cannon!

Jeff

--
Jeffrey Kain
[hidden email]

> On Feb 22, 2017, at 1:27 PM, Cannon Smith via 4D_Tech <[hidden email]> wrote:
>
> Hi Jeff,
>
>> If ((JSON Stringify($fieldPtr->))#(JSON Stringify(Old($fieldPtr->))))
>
> This only works if the order of the keys in the object stays the same which may not be true depending on how you change the object. I’ve pasted in a method below that you can use to compare two objects which don’t care about the order of keys. I use it in a similar situation to what you are doing and it works well.
>
> The method name is “OBJ_IsEqual”. It calls itself, so if you use a different name make sure you change that in the code.
>
> Vincent de Lachaux posted the original code which I then stole. :-)

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
In reply to this post by 4D Tech mailing list
Jeff,

On Wed, Feb 22, 2017 at 10:03 AM, Jeffrey Kain via 4D_Tech <
[hidden email]> wrote:

> Doesn't Modified only work in a form event?
>
​Yep - my bad.


> So it turns out that Old works fine with an object field, but you can't do
> an = comparison. I think what I'm going to do is the following:
>
>   If ((JSON Stringify($fieldPtr->))#(JSON Stringify(Old($fieldPtr->))))
>
> Seems really inefficient, but it works.
>
​It is inefficient. But JSON is specifically un-ordered and fluid.
Personally in situations where I store data in c-objects like this I just
re-write the c-object - it's usually no more time than testing to see if I
need to re-write it.

Another trick I use is to maintain a separate field with the timestamp of
when the JSON was written. When it's actually requested look at the
timestamp for the last time the record was modified. If they are the same
just return the JSON, if they are different re-write the JSON. This is good
in cases where the record changes a lot but only gets read occasionally -
or never.

--
Kirk Brooks
San Francisco, CA
=======================
**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
In reply to this post by 4D Tech mailing list

> Le 22 févr. 2017 à 19:27, Cannon Smith via 4D_Tech <[hidden email]> a écrit :
>
> [...]
> Vincent de Lachaux posted the original code which I then stole. :-)

Being stolen is sometimes flattering  ;-)


>  : ($atFirstProperty{$x}#$atSecondProperty{$x})  //Check property name

About the comparison above, json properties are case sensitive.
Things like:
  :(Position(atFirstProperty{$x};$atSecondProperty{$x};*)=1)
or
  :(Find regex(atFirstProperty{$x};$atSecondProperty{$x};1))
Wouldn't it be safer?

--
Arnaud de Montard


**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
In reply to this post by 4D Tech mailing list
> Seems really inefficient, but it works

4D has taken pains to say that object fields *are not JSON*. They can be
represented as JSON, but they aren't stored or accessed as JSON internally.
So, it does seem like a good bug report/feature request to make Old work
correctly on object fields. In fact, it's probably one of the more
important field types that it could work on it. Having to serialize it and
run an expensive comparison ourselves feels a bit over the top.

If you put in a feature request/bug report, shoot a note over here so that
any of us that care can go and vote for your idea.

Speaking of objects and feature requests, Cannon "Object Module" Smith made
a fantastic feature request the other day:

http://forums.4d.fr/Post/EN/19051683/1/19051684

The idea is to have an automatic, internal C_OBJECT-type structure (a
dictionary) maintained by 4D for each widget on a form. If they did this,
you wouldn't see anything different on the form, but if you wanted to
associated custom attributes or data with the widget (rules, bindings,
hints, extra lookup data, filters, formats, privileges, etc.), you would
know right where to get/set the data. It may sound like a small thing, but
it would be a *huge* win. Just massive. You can do something on this order
now with a custom C_OBJECT in a form or process, but the init/cleanup cycle
is kind of 'heavy'. Also, that makes the price of admission high enough
that most people won't do it. Many will never even have the chance to
understand why this is such a great, great idea. If the feature were built
in, people would fall into it and quickly feel like it was always there.

I find myself promoting Cannon's idea becuase it's just so darn good that
if I don't, I'll quickly forget where I heard it and then later "invent" it
myself ;-) I used to work with a guy and I'd come in some mornings and say:
"I've had this amazing idea! You're going to LOVE it!" Blank stare. Answer
"Yeah, I loved it yesterday when I told it to you." Cryptomnesia. It's a
thing. Anyway, please go consider and vote for Cannon's idea. Between me
and Peter Hay I think we've gotten the vote count into the low hundreds ;-)
(Peter and I are adding +100 on this feature request.)

http://forums.4d.fr/Post/EN/19051683/1/19051684
**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
Yeah, that's an incredibly good idea.  I think it would also be very useful for tables as well - being able to manage metadata for a table without creating a special record has been on my wish list for decades now...

> On Feb 22, 2017, at 7:12 PM, David Adams via 4D_Tech <[hidden email]> wrote:
>
> The idea is to have an automatic, internal C_OBJECT-type structure (a
> dictionary) maintained by 4D for each widget on a form. If they did this,
> you wouldn't see anything different on the form, but if you wanted to
> associated custom attributes or data with the widget (rules, bindings,
> hints, extra lookup data, filters, formats, privileges, etc.), you would
> know right where to get/set the data.

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
On Thu, Feb 23, 2017 at 12:14 PM, Jeffrey Kain via 4D_Tech <
[hidden email]> wrote:

> Yeah, that's an incredibly good idea.  I think it would also be very
> useful for tables as well - being able to manage metadata for a table
> without creating a special record has been on my wish list for decades
> now...
>
> +100 on that one too. Great idea. It seems like anything beyond a toy
system needs an extended attributes table for tables and fields. It would
be fantastic to have a hook to add that too. The, of course, we would need
tools to search on attributes...but 4D's object fields already have tools
of that sort. Seems like a very natural and awesome feature request - give
us a place to store and manage custom attributes. But don't make us add
another table (etc.) to do it. Nice one. Please put in a feature request
and maybe we can get a crew to sign it.

And, while we're at it, it would be nice for forms to have such an
extension as well.

It really does seem like 4D has all of the internal tools to do this pretty
easily. Easy for me to say, but the pieces sure seem to be right there now.
Could make for some very cool Summit demos and, better, some super happy
customers.
**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
while I love discussing feature requests,
I also take the pragmatic view that every new feature comes at the cost of an idea delayed if not discarded.

so,
if anything is already possible with a little bit of creativity,
and fulfils the immediate need,
I would be ready to accept that,
to clear the way for more important stuff.

take the idea of table meta:

very limited (read-only), I understand,
but it is possible to use the "comment" property.
http://doc.4d.com/4Dv16/4D/16/Table-properties.300-3048984.en.html <http://doc.4d.com/4Dv16/4D/16/Table-properties.300-3048984.en.html>

something like...

$structure:=""
EXPORT STRUCTURE($structure)

$dom:=DOM Parse XML variable($structure)

  //seems only <table> has an id attribute; alternatively traverse the tree
$tableId:=String(Table(->[Table_1]))
$table:=DOM Find XML element by ID($dom;$tableId)

  //need to init array in case "find element" returns nothing
ARRAY TEXT($comments;0)
$comment:=DOM Find XML element($table;"table/table_extra/comment";$comments)
CLEAR VARIABLE($comment)
For ($i;1;Size of array($comments))
DOM GET XML ATTRIBUTE BY NAME($comments{$i};"format";$format)
  //there is also an rtf format
If ($format="text")
DOM GET XML ELEMENT VALUE($comments{$i};$comment)
End if
End for

DOM CLOSE XML($dom)

  //for example...
$meta:=JSON Parse($comment;Is object)





**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
On Thu, Feb 23, 2017 at 1:45 PM, Keisuke Miyako via 4D_Tech <
[hidden email]> wrote:

> while I love discussing feature requests,


You make a good point about feature requests, but I've got another point of
view. Sometimes, it's better for 4D to implement a feature than for us to
implement it. In the case of a meta-object/extended attributes for form
objects, forms, fields, tables, etc., there are possible solutions already.
Sure, you can write that sort of code. But here's the thing, to do that
*you already have to have a pretty solid understanding of how to do that
and why.* People that work exclusively in 4D aren't necessarily likely to
already have that knowledge (how would they?) or to invent it (inventing
stuff is hard and rare.) If its in the box, it's easy to sick your toe in,
experiment with and go from there.

Does 4D Engineering always get it right on figuring out what to prioritize.
No, no they do not. Sometimes they give us totally awesome stuff I never
would have thought to ask for, sometimes I'm left scratching my head.
Sometimes they miss an opportunity. Do you know the first time I heard the
idea of "local form variables" (what we have today with form object names)
brought up? It was over 25 years ago. What if we *had* gotten that feature
25 years ago? How many people use it now that never even realized it was
missing? Lots. At the time, the idea was mocked. (Not sure why, it always
seemed like a good idea on the face of it.)

I guess my (hopefully useful) point is that by implementing something
nicely (like CALL PROCES, CALL FORM and C_OBJECT to a lesser degree), lots
of people can take advantage of them. So, low price of admission for doing
something useful and doing it well. Isn't that what 4D's all about? If the
price is "you already have to understand this well enough to write it
yourself in tools not quite written for that purpose" or "you have to write
it using a plug-in", well, you don't really make 4D as good as it could be.

Meta-objects/extended attributes/custom dictionaries are *fundamentally*
useful and would make 4D *instantly* better for all developers, not just
the developers with the background, time, and inclination to write their
own system. Also, then you would have skill and code transferability
between projects. A new developer can jump into a project and already know
how to use extended attributes because it's a 4D feature, not a custom bit
of code.

Anyway, that's how I see it.

If anyone needs a list of benefits of having little custom dictionaries
extending 4D objects, it's probably better to do it over on an official
feature request thread on the Forums in France. Here on the NUG, we're just
talking.
**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields....or rather Objects in General

4D Tech mailing list
In reply to this post by 4D Tech mailing list
David

This slightly changes the topic of the OLD on Object fields to a more detailed discussion of the ‘shortcomings' of objects….

(On the topic of the former in my case if I am creating an object in code its likely to be created with the same key order each time so if the ’stringified' version old is not =current then its changed-and even if it was not in the same order it has changed so it is modified).

Dealing with the Form Meta data..I would really like it if 4D implemented the object and form meta data concept because you could extract easily the entire representation of a form which is what I currently do with some really interesting code-and i know  a number of others have done similar-maybe those of us who are interested in such could pool our code and end up with a common concept of the structure of the Meta object (Object keys named in a common way, common thinking of how to represent form elements etc)-waiting for 4D could be a while-probably there is stuff other people are doing that is better than mine.

I will throw some stuff here..if you or others  want to work this up feel free to come back to me:

There are a couple of Form Propeties and Object properties you cant(I think) get. This was a note i made in my code

 //the following form settings cannot be obtained in code(V14)
  //Markers
  //access
  //menu bar
  //print settings
  //appearance
  //form type
  //inherited form table
  //inherited form name
  //save geometry

and there is an interesting problem that occurs if you have an inherited form(took me a while to work out what the hell was going on)…if an inherited form has an object named ‘variable1’ and the form itself also has ‘variable1’ When you parse the form you get the objects of the form and the objects of the inherited form. When you get the variable associated with ‘variable1’ you might get the one from the form or the one from the inherited form..and it seems random which order you get the objects in-i had to make sure my object names on inherited forms where unique.


For your delectation I have put a copy of my version of a  form export (this is for a very basic auto made 4D form-i have some really complex forms-and the code building this may not be perfect) on my dropbox-

https://www.dropbox.com/s/sr3xfqrxfqton1p/FORM_PO_Purchase_Order_Item_Input.txt?dl=0 <https://www.dropbox.com/s/sr3xfqrxfqton1p/FORM_PO_Purchase_Order_Item_Input.txt?dl=0>

(Its easier as a human to read this if you replace the , with cr)

I build an object with the data put the object in a blob and create a document for safe keeping. In Previous attempts at this I used XML and boy did that get ugly!  I have code that reads this format back in and is able to compare the current version of a form with a saved version of the form-I do not have fancy code that reads this and creates or fixes a form or anything, it just tells me what has physically changed.

I would propose:
1) A common way for creating a form(and its objects) in an object.
2) A common way for comparing two complex objects where the ‘structure’ of the objects is known producing a either a human readable(string) of changes or an object representing the changes. e.g a way of comparing two representations of a form.

Let know if you or others are interested.

Nigel Greenlee


> On 23 Feb 2017, at 00:12, David Adams via 4D_Tech <[hidden email]> wrote:
>
>> Seems really inefficient, but it work
>
> 4D has taken pains to say that object fields *are not JSON*. They can be
> represented as JSON, but they aren't stored or accessed as JSON internally.
> So, it does seem like a good bug report/feature request to make Old work
> correctly on object fields. In fact, it's probably one of the more
> important field types that it could work on it. Having to serialize it and
> run an expensive comparison ourselves feels a bit over the top.
>
> If you put in a feature request/bug report, shoot a note over here so that
> any of us that care can go and vote for your idea.
>
> Speaking of objects and feature requests, Cannon "Object Module" Smith made
> a fantastic feature request the other day:
>
> http://forums.4d.fr/Post/EN/19051683/1/19051684
>
> The idea is to have an automatic, internal C_OBJECT-type structure (a
> dictionary) maintained by 4D for each widget on a form. If they did this,
> you wouldn't see anything different on the form, but if you wanted to
> associated custom attributes or data with the widget (rules, bindings,
> hints, extra lookup data, filters, formats, privileges, etc.), you would
> know right where to get/set the data. It may sound like a small thing, but
> it would be a *huge* win. Just massive. You can do something on this order
> now with a custom C_OBJECT in a form or process, but the init/cleanup cycle
> is kind of 'heavy'. Also, that makes the price of admission high enough
> that most people won't do it. Many will never even have the chance to
> understand why this is such a great, great idea. If the feature were built
> in, people would fall into it and quickly feel like it was always there.
>
> I find myself promoting Cannon's idea becuase it's just so darn good that
> if I don't, I'll quickly forget where I heard it and then later "invent" it
> myself ;-) I used to work with a guy and I'd come in some mornings and say:
> "I've had this amazing idea! You're going to LOVE it!" Blank stare. Answer
> "Yeah, I loved it yesterday when I told it to you." Cryptomnesia. It's a
> thing. Anyway, please go consider and vote for Cannon's idea. Between me
> and Peter Hay I think we've gotten the vote count into the low hundreds ;-)
> (Peter and I are adding +100 on this feature request.)
>
> http://forums.4d.fr/Post/EN/19051683/1/19051684
> **********************************************************************
> 4D Internet Users Group (4D iNUG)
> FAQ:  http://lists.4d.com/faqnug.html
> Archive:  http://lists.4d.com/archives.html
> Options: http://lists.4d.com/mailman/options/4d_tech
> Unsub:  mailto:[hidden email]
> **********************************************************************

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list
In reply to this post by 4D Tech mailing list
Hi Arnaud,

> On Feb 22, 2017, at 2:25 PM, Arnaud de Montard via 4D_Tech <[hidden email]> wrote:
>
>> : ($atFirstProperty{$x}#$atSecondProperty{$x})  //Check property name
>
> About the comparison above, json properties are case sensitive.
> Things like:
>  :(Position(atFirstProperty{$x};$atSecondProperty{$x};*)=1)

Thanks! You are right, the code does not handle case sensitivity for property names correctly. Below is the corrected code for anyone that wants to replace the OBJ_IsEqual code directly. (I’ll post updated versions of the OBJ module a little later today.)

Nice catch!

--
Cannon.Smith
Synergy Farm Solutions Inc.
Hill Spring, AB Canada
403-626-3236
<[hidden email]>
<www.synergyfarmsolutions.com>


  //Compares two objects. If they are the same (ie. they have exactly the same elements and values),
  //the method returns true. Thanks to Vincent de Lachaux for the original code which has been changed
  //slightly to more closely match my style.

C_OBJECT($1;$oFirst)
C_OBJECT($2;$oSecond)
C_BOOLEAN($0;$fIsEqual)

$oFirst:=$1
$oSecond:=$2
$fIsEqual:=False  //Defaul to false

C_LONGINT($x;$y;$lFirstItemCount;$lSecondItemCount;$lFirstPropertyCount;$lSecondPropertyCount)
ARRAY LONGINT($alFirstType;0)
ARRAY TEXT($atFirstProperty;0)
ARRAY LONGINT($alSecondType;0)
ARRAY TEXT($atSecondProperty;0)

OB GET PROPERTY NAMES($oFirst;$atFirstProperty;$alFirstType)
OB GET PROPERTY NAMES($oSecond;$atSecondProperty;$alSecondType)
$lFirstPropertyCount:=Size of array($atFirstProperty)
$lSecondPropertyCount:=Size of array($atSecondProperty)

If ($lFirstPropertyCount=$lSecondPropertyCount)  //They won't be equal if they have different property counts
        If ($lFirstPropertyCount>0)
                  //Sort arrays because the properties could be in a different order
                SORT ARRAY($atFirstProperty;$alFirstType)
                SORT ARRAY($atSecondProperty;$alSecondType)
               
                  //Now compare each property
                For ($x;1;$lFirstPropertyCount)
                       
                        Case of
                                : (Length($atFirstProperty{$x})#Length($atSecondProperty{$x}))  //If the property names aren't the same length
                                        $fIsEqual:=False
                                       
                                : (Position($atFirstProperty{$x};$atSecondProperty{$x};*)#1)  //Check property name (case sensitive)
                                        $fIsEqual:=False
                                       
                                : ($alFirstType{$x}#$alSecondType{$x})  //Check property type
                                        $fIsEqual:=False
                                       
                                : ($alFirstType{$x}=Is object)
                                          //compare the two objects
                                        $fIsEqual:=OBJ_IsEqual (\
                                        OB Get($oFirst;$atFirstProperty{$x};Is object);\
                                        OB Get($oSecond;$atFirstProperty{$x};Is object))
                                       
                                : ($alFirstType{$x}=Object array)
                                          //In an object array we can massage all the array types back into text except object themselves.
                                          //So we get two sets of arrays, one text and the other objects. Then we can deal with either kind
                                          //as we walk through each element.
                                       
                                        ARRAY OBJECT($aoFirst;0)  //Reset arrays
                                        ARRAY TEXT($atFirst;0)
                                        ARRAY OBJECT($aoSecond;0)
                                        ARRAY TEXT($atSecond;0)
                                        OB GET ARRAY($oFirst;$atFirstProperty{$x};$aoFirst)  //Get text and object types
                                        OB GET ARRAY($oFirst;$atFirstProperty{$x};$atFirst)
                                        OB GET ARRAY($oSecond;$atFirstProperty{$x};$aoSecond)
                                        OB GET ARRAY($oSecond;$atFirstProperty{$x};$atSecond)
                                       
                                        $lFirstItemCount:=Size of array($aoFirst)
                                        $lSecondItemCount:=Size of array($aoSecond)
                                        If ($lFirstItemCount=$lSecondItemCount)
                                                For ($y;1;$lFirstItemCount;1)
                                                        If ((OB Is defined($aoFirst{$y})) & (OB Is defined($aoSecond{$y})))  //If they are both objects
                                                                $fIsEqual:=OBJ_IsEqual ($aoFirst{$y};$aoSecond{$y})
                                                        Else   //Compare text
                                                                $fIsEqual:=($atFirst{$y}=$atSecond{$y})
                                                        End if
                                                        If ($fIsEqual=False)
                                                                $y:=$lFirstItemCount+1  //Abort loop
                                                        End if
                                                End for
                                        Else
                                                $fIsEqual:=False
                                        End if
                                       
                                Else   //For any other object type, we simply compare the values
                                        $fIsEqual:=(OB Get($oFirst;$atFirstProperty{$x})=OB Get($oSecond;$atFirstProperty{$x}))
                                       
                        End case
                       
                        If ($fIsEqual=False)
                                $x:=$lFirstPropertyCount+1  //Abort loop
                        End if
                       
                End for
               
        Else   //If there are not elements in either one, they are both equal
                $fIsEqual:=True
        End if
End if

$0:=$fIsEqual

**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Old doesn't work with object fields

4D Tech mailing list

> Le 23 févr. 2017 à 18:17, Cannon Smith via 4D_Tech <[hidden email]> a écrit :
>
> Hi Arnaud,
>
> You are right, the code does not handle case sensitivity for property names correctly. [...]

now it's perfect to be stolen  ;-)

Many thanks!

--
Arnaud de Montard



**********************************************************************
4D Internet Users Group (4D iNUG)
FAQ:  http://lists.4d.com/faqnug.html
Archive:  http://lists.4d.com/archives.html
Options: http://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************