CALL FORM: Some notes on a command that's easy to misunderstand

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

CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
I've seen CALL FORM come up in some recent threads where people have
mistaken ideas about how it works. I think that the mistakes are entirely
natural when coming from CALL PROCESS/On Outside call. I was going to add
some comments to the docs, but I just looked and don't see how you do it.
Presumably there's something you need to log into first (?) Instructions
appreciated. For now, here are a few notes:

Q: What form event is triggered by CALL FORM?
A: None.

Q: How does the form method know it's being called via CALL FORM?
A: Trick question. The form method isn't called. You specify what method is
called in the CALL FORM command itself.

Q: What does CALL FORM have to do with CALL PROCESS and On Outside Call?
A: In most cases, it replaces them with a superior mechanism. The old tools
still work, but CALL FORM offers a lot more possibilities and much better
reliability and control.

That's some basic stuff - and I think I'm just highlighting what the docs
already say. Conceptually, I think it's helpful to think of the command as

CALL FORM WINDOW

The "message queue" (see more below) *does not belong to the form.* When
you CALL FORM, *it is not the form that catches the call.* You can prove
this for yourself pretty easily. Here's a write-up I sent to Thomas Maul
for comment:

C_LONGINT($winref)
$winref:=Open form window("MyForm")
CALL FORM($winref;"MyForm_Setup";"Call form method parameter")
DIALOG("MyForm")

The queue is able to receive a message as soon as the window is defined and
before any form is associated with the window. That’s fine, but I wondered
about processing sequence. I tried it out and here is what I found:

* You can post a message to the queue before the form is opened (as in your
demo.)
* On Load executes.
* Then the pre-posted message is executed.

If you post a message to the queue from within On Load, then it is executed
after the message posted before the form was opened.

All of this behavior seems perfectly sensible to me, but it isn’t
documented one way or the other. Is this sequence of events something that
we can rely on? I expect that some 4D developers using this tool are very
likely to find it important exactly how On Load and the queue are sequenced.

Thomas very kindly got an answer about this from 4D Engineering. I think it
translates more-or-less exactly as "yes" ;-) So, this is a reliable
behavior:

* Open window
* Post calls with CALL FORM _even though there is no form_
* Load a form
* Post more events in On Before
* On Before finishes
* The calls posted _before_ the form opened run
* The calls posted _within_ On Before run.

Confusing? A little, but try it out - it's not bad at all. Here's what I
recommend:

* Open window
* Open form
* Run On Before and do what you need directly

Much easier to follow.

A bit more about the 'queue'. A message queue is normally a block of data -
think a bunch of parameters formatted as JSON, in some binary format, XML,
etc. That's not what 4D's "messages" are, they're commands. In fact, the
best names for the new commands are probably these:

EXECUTE METHOD IN WINDOW
EXECUTE METHOD IN WORKER

That's what's really happening. When you call a window or a worker, you're
pushing a line of code over for execution *within* that worker or window.
So, the code comes from the outside and is executed in the context of the
target window or worker. It has nothing to do with the form itself, from
out point of view.

There's a ton more to say about all of this, but that's all I've got time
for now.

Questions, comments, and corrections are very welcome. I think that these
new commands are great and that people should get excited about them. Just
playing with them for a couple of hours when you're relaxed is probably
enough to give you the bug. So, please, kick off questions and thoughts -
there are tons of great uses for these commands - I'd love to hear what
people are doing. Particularly simple things. I suck at simple examples...I
tend to write long...but everyone knows that already ;-)
**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
Forgot to mention, it might be worth renaming the commands for clarity so I
put in a feature request the other day and then revised it before the post
above. Here's the link if anyone agrees and feels like voting for it:

http://forums.4d.fr/Post//19157490/1/
**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
OK, so it's Friday afternoon and I've got a few moments while I sup on a cold bevvy. David & I kind of got the fervour about CALL FORM/WORKER at the same time and this is one of the things about them that really captured our imagination.

We are using CALL FORM and CALL WORKER to automate unit testing of our forms. This has been something we've been wanting to do for a very long time but has been impossible or at the very least impractical prior to the introduction of these two commands.

There is very little cost to setting it up if you implement your form and object methods as separate project methods, and if you use meaningful names for the objects on the form.

The beauty of this system is that the forms and their associated methods are driven completely externally, so they need to have absolutely no extra logic built in to handle the messaging. Furthermore, the control methods for driving it are completely generic. The only thing that needs any knowledge of the form interactions is the method that's describing the unit tests.

We have a small number of message types that can be sent to the form. These are things like:
 - set a value (could apply to any object on the form, e.g. field, button, checkbox, listbox, etc.)
 - delay for a number of ticks
 - trigger a form or object event

These messages are created as C_OBJECTs, e.g. we have a method UT_UIMessageSetTextValue. This takes an object name and a text value as parameters and returns a C_OBJECT representing that message. We have methods to set different data types, trigger a form or object event, delay, etc. We can then create a queue of these messages and send them to a worker process for delivery to the form (window). We have a generic method to do all of this, which takes one or more of the C_OBJECT messages, creates another C_OBJECT containing the current process number and an OBJECT ARRAY of the supplied messages, and then passes that object (using CALL WORKER) to a worker process.

So a simple example of driving a wrapper for the Request dialog might look like this:


$vT_ExpectedResult:="Some Value"
UT_UIMessageQueue(\
        UT_UIMessageSetTextValue ("Response_Fld";$vT_ExpectedResult);\
        UT_UIMessageDelay (30);\
        UT_UIMessageSetLongintValue ("OK_Btn";1);\
        UT_UIMessageTriggerEvent ("DLG_RequestFM";On Clicked))
 
$vT_ActualResult:=WRAP_Request ("Enter a value")

ASSERT($vT_ActualResult=$vT_ExpectedResult;"Unexpected response")


The worker process determines the correct window reference (the frontmost window for the process contained in the C_OBJECT it receives), waits for that window to load, and iterates through the queue of C_OBJECTS. If it's a delay message, the delay is actually performed in the worker. If it's an event, the form or object's project method is called using CALL FORM, passing the event to be triggered. Otherwise the message is sent to a "broker" method using CALL FORM which sets the requested object value.

It sounds complicated, trying to write it all out, but the framework is actually beautifully simple. It just consists of a handful generic methods, none of which extends to more than about 40 lines of code:

- UT_UIMessageSet<XXX>Value
- UT_UIMessageDelay
- UT_UIMessageTriggerEvent
- UT_UIMessageQueue
- UT_UIWorker
- UT_UIBroker

And strictly speaking the delay capability is probably not necessary, but it's kinda cool watching the form objects update as if by magic in front of your eyes.

Oh and +1 for the proposed command name changes - definitely clarifies the functions of these two commands.

Regards
Justin Carr
Genie Solutions
**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

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

Yes, you need to log in.

Notes are only available at livedoc.4d.com <http://livedoc.4d.com/>. (There is NO note feature at doc.4d.com <http://doc.4d.com/>.)

The login link is at the top right of the web page.

https://s8.postimg.org/oylrfbtsl/p01_comment_log_in.png

Scroll down to the “Previous Page” and “Next Page” buttons, and click “Add Comment”.

https://s15.postimg.org/e0nqetxt7/p2_add_comment_button.png <https://s15.postimg.org/e0nqetxt7/p2_add_comment_button.png>

A “window” opens in which to write the comment.

https://s21.postimg.org/k4j2wzss7/p03_add_a_comment.png


Jeremy French


> On Mar 16, 2017, at 10:28 PM, David Adams via 4D_Tech <[hidden email]> wrote:
>
> I was going to add some comments to the docs, but I just looked and don't see how you do it.
> Presumably there's something you need to log into first (?) Instructions appreciated.

**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

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

Interesting approach - thank you for posting that.

Lacking "callers" and C_Object, I've been using On outside call +
ObjectTools + IP messaging based on the ITK message queuing system. I'm not
sure if this is germane to Call form/worker but I include a "reply to ID"
in the message that's sent. Most of the time, if the called code needs to
reply, the reply is directed to the calling process but there are times
when I've wanted the called code to pass the result to another process.


My projects are just moving to 15.x now so Call worker/call form are still
a bit out of reach for me but I'm glad to see that these have been added to
the language. They're a natural outgrowth of OOC, Call subform container,
etc., and we *finally* have a way to communicate with those windows opened
in the asterisk.



--
Douglas von Roeder
949-336-2902

On Fri, Mar 17, 2017 at 12:22 AM, Justin Carr via 4D_Tech <
[hidden email]> wrote:

> OK, so it's Friday afternoon and I've got a few moments while I sup on a
> cold bevvy. David & I kind of got the fervour about CALL FORM/WORKER at the
> same time and this is one of the things about them that really captured our
> imagination.
>
> We are using CALL FORM and CALL WORKER to automate unit testing of our
> forms. This has been something we've been wanting to do for a very long
> time but has been impossible or at the very least impractical prior to the
> introduction of these two commands.
>
> There is very little cost to setting it up if you implement your form and
> object methods as separate project methods, and if you use meaningful names
> for the objects on the form.
>
> The beauty of this system is that the forms and their associated methods
> are driven completely externally, so they need to have absolutely no extra
> logic built in to handle the messaging. Furthermore, the control methods
> for driving it are completely generic. The only thing that needs any
> knowledge of the form interactions is the method that's describing the unit
> tests.
>
> We have a small number of message types that can be sent to the form.
> These are things like:
>  - set a value (could apply to any object on the form, e.g. field, button,
> checkbox, listbox, etc.)
>  - delay for a number of ticks
>  - trigger a form or object event
>
> These messages are created as C_OBJECTs, e.g. we have a method
> UT_UIMessageSetTextValue. This takes an object name and a text value as
> parameters and returns a C_OBJECT representing that message. We have
> methods to set different data types, trigger a form or object event, delay,
> etc. We can then create a queue of these messages and send them to a worker
> process for delivery to the form (window). We have a generic method to do
> all of this, which takes one or more of the C_OBJECT messages, creates
> another C_OBJECT containing the current process number and an OBJECT ARRAY
> of the supplied messages, and then passes that object (using CALL WORKER)
> to a worker process.
>
> So a simple example of driving a wrapper for the Request dialog might look
> like this:
>
>
> $vT_ExpectedResult:="Some Value"
> UT_UIMessageQueue(\
>         UT_UIMessageSetTextValue ("Response_Fld";$vT_ExpectedResult);\
>         UT_UIMessageDelay (30);\
>         UT_UIMessageSetLongintValue ("OK_Btn";1);\
>         UT_UIMessageTriggerEvent ("DLG_RequestFM";On Clicked))
>
> $vT_ActualResult:=WRAP_Request ("Enter a value")
>
> ASSERT($vT_ActualResult=$vT_ExpectedResult;"Unexpected response")
>
>
> The worker process determines the correct window reference (the frontmost
> window for the process contained in the C_OBJECT it receives), waits for
> that window to load, and iterates through the queue of C_OBJECTS. If it's a
> delay message, the delay is actually performed in the worker. If it's an
> event, the form or object's project method is called using CALL FORM,
> passing the event to be triggered. Otherwise the message is sent to a
> "broker" method using CALL FORM which sets the requested object value.
>
> It sounds complicated, trying to write it all out, but the framework is
> actually beautifully simple. It just consists of a handful generic methods,
> none of which extends to more than about 40 lines of code:
>
> - UT_UIMessageSet<XXX>Value
> - UT_UIMessageDelay
> - UT_UIMessageTriggerEvent
> - UT_UIMessageQueue
> - UT_UIWorker
> - UT_UIBroker
>
> And strictly speaking the delay capability is probably not necessary, but
> it's kinda cool watching the form objects update as if by magic in front of
> your eyes.
>
> Oh and +1 for the proposed command name changes - definitely clarifies the
> functions of these two commands.
>
> Regards
> Justin Carr
> Genie Solutions
> **********************************************************************
> 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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
In reply to this post by 4D Tech mailing list
> On Fri, Mar 17, 2017 at 6:22 PM, Justin Carr via 4D_Tech wrote:

> OK, so it's Friday afternoon and I've got a few moments while I sup on a
cold
> bevvy.

Hey J, thanks for chiming in!

> David & I kind of got the fervour about CALL FORM/WORKER at the same
> time and this is one of the things about them that really captured our
> imagination.

I have Justin to thank for getting me to jump to V16. And the idea he
outlines in his post is *very* cool. As Justin points out, it's actually
simpler in the code than it is to explain! If you grasp this idea, you'll
have a pretty high level mastery of how the CALL FORM and CALL WORKER
commands work.

> We are using CALL FORM and CALL WORKER to automate unit testing of our
forms.
> This has been something we've been wanting to do for a very long time but
has
> been impossible or at the very least impractical prior to the
introduction of
> these two commands.

A side note for those following along at home. Eggplant is the name that
comes up at this point amongst people that know about automated testing.
And Justin and his group have looked at Eggplant. For those of you that
don't know already, Eggplant is a long-established GUI testing suite that
works in a novel way. Rather than tap into the APIs for UI widgets on a
specific platform, it compares screenshots. That's a pretty crude summary
as Eggplant is vastly more sophisticated than that - but the basic
technology is to compare screen components (text, images, etc.) with
current screen contents. It's scriptable, flexible and pretty impressive.
It's virtue is that it works like a sort of automated user - one that can
spot when something has changed (an icon is different, the expected text
did not appear, a weird window showed up, a button click does nothing,
etc.) It's virtue is also it's weakness. Namely, that it doesn't get under
the skin. Sometimes what you want to test is not the UI itself, it's the
behaviors that the UI drives. Say you've got a drop-down, an entry area, a
button, and a display variable. You want to test what happens when you
select different items from the dropdown - say a discount rate or a post
code, whatever - and different values in the entry area. The button click
runs a calculation and the result appears in the display area. Perhaps you
could do that with Eggplant, but there are times when it's more involved
and you can't. So, with Justin's approach, you get to pass in instructions
for setting values (the popup and the entry area), clicking things (the
button)...and you are inside of 4D code. Meaning, you can test the outcome.
The outcome might be how a variable is set, what selection of records is
found, etc.

Now, if all of your code were structured as perfect little headless APIs
that you could write headless test code for then, well, then you probably
wouldn't be on this list. Who has massive code bases going back to the
1980s and 1990s? I'm seeing a lot of people raising their hands;-) Between
Justin's solution and Eggplant, there's not a lot of GUI-driven testing
that you can't do. I know that formal testing is (understandably) not of
great interest to many one-person development organizations, but it is a
very big deal to larger organizations, particularly ones that face
regulatory scrutiny of any kind.

Note: Someone from Pelican Engineering did an automated testing some years
back at a 4D Summit that included discussion of Eggplant. It was a very
well-received event. Sorry, I don't remember the year or other details.

> There is very little cost to setting it up if you implement your form and
> object methods as separate project methods, and if you use meaningful
names
> for the objects on the form.

Both really good points. To take advantage of CALL FORM, you're much better
off having form methods and objects that call a global method or methods. I
started 1+ thread(s) on this subject in the past couple of months for this
very reason. Meaningful object names are a good call for this sort of
system. Instead of passing pointers, you pass object names and derive
pointers on the recipient side.

> The beauty of this system is that the forms and their associated methods
are
> driven completely externally, so they need to have absolutely no extra
logic
> built in to handle the messaging. Furthermore, the control methods for
driving
> it are completely generic. The only thing that needs any knowledge of the
form
> interactions is the method that's describing the unit tests.

It's a real thing of beauty to behold. There's no special test mode that
you have to add to your code. Your code stays the same! You just now have
the scriptable tool to provoke the items on the form. So nice. It's a bit
hard to grasp exactly how easy and cool this is until you see it. But it
really is easy and cool. Well, "easy" once Justin figures it all out in
about an hour ;-)

> We have a small number of message types that can be sent to the form....
> It sounds complicated, trying to write it all out, but the framework is
> actually beautifully simple. It just consists of a handful generic
methods,
> none of which extends to more than about 40 lines of code
If you're implementing this at home, you'll know you've got it right if you
also need only a handful of small methods to do what Justin describes.

> It sounds complicated, trying to write it all out, but the framework is
> actually beautifully simple. It just consists of a handful generic
methods,

> none of which extends to more than about 40 lines of code:
>
> - UT_UIMessageSet<XXX>Value
> - UT_UIMessageDelay
> - UT_UIMessageTriggerEvent
> - UT_UIMessageQueue
> - UT_UIWorker
> - UT_UIBroker
>
> And strictly speaking the delay capability is probably not necessary, but
it's
> kinda cool watching the form objects update as if by magic in front of
your
> eyes.

;-) If your form were expecting some other even to happen from some other
process, then they delay might be super helpful.

For those of you that haven't made the connection, Justin is the same
person that gave us the 4D DebugLogReader tool:

https://github.com/j-genie
**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
In reply to this post by 4D Tech mailing list
> Interesting approach - thank you for posting that.

DvR: You, of all people, will *love* this approach.

> Lacking "callers" and C_Object, I've been using On outside call +
> ObjectTools + IP messaging based on the ITK message queuing system.

Once you have access to V16, you may find:

* You like C_OBJECT because it's very fast and native. But it won't do
everything that ObjectTools does.

* You may still want to use IPC channels from NTK. They're traditional
messages, easily support a wider range of messaging patterns, and can be
used to-from anywhere.

* CALL FORM/CALL WORKER are great! You'll love them. On Outside Call was
always documented as being unreliable while CALL FORM / CALL WORKER
guarantee delivery. (Unless you kill a worker, kill a process, kill 4D, or
crash. But, hey, that's pretty reasonable for a lot of situations.)

> I'm not sure if this is germane to Call form/worker but I include a
"reply to ID"
> in the message that's sent.

Yes, that can be entirely relevant. These 'calls' aren't a channel, you're
tossing blocks of code at the end of the thread of control over there for
one-off execution. There is no return message. You can send along callback
details if, for example, you need a result. There are times when you'll
find NTK's IPC channels easier. And, yes, message discipline is _super_
beneficial. You mention that you're doing message routine. This can be
pretty darn impossible to trace or debug if there's nothing in the message
about the path that it has followed.

Tip: I've found it helpful to define a 'recipient' object as a specific
type. This can be the recipient of a CALL FORM/CALL WORKER message or the
callback details when you want a result, error, or confirmation message
returned. By treating this as a custom data type, it's easy to have a
single method for creating recipients and for validating them. "Validating"
matters if you, for example, want to be sure that method names exist and
that window refs are valid.

> My projects are just moving to 15.x now so Call worker/call form are still
> a bit out of reach for me but I'm glad to see that these have been added
to
> the language. They're a natural outgrowth of OOC, Call subform container,
> etc., and we *finally* have a way to communicate with those windows opened
> in the asterisk.

Yeah, you'll love it. Given our existing framework, you'll feel like some
things are missing - so keep NTK around. Also, vote for a native WebSockets
implementation. This would be an *amazingly* great addition to 4D. You
could have a persistent, bi-directional, point-to-point pipe between
processes on one machine or different machines. Game changer.

WebSocket protocol on 4D webserver
http://forums.4d.fr/Post/EN/19129127/1/19129128
**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
David:

I'll read up on the web sockets - when I first saw that I misread it for
"WebObjects". A cold chill ensued.

C_Object is a great addition to the language. Agree that it doesn't do
everything that OT does but that why we have wrapper routines. I've
extended Cannon's OBJ_Module with OBJ_SetArray_Text/Long/Real and a few
other array commands and I can get a lot done with C_Object that I'm doing
in OT. The biggest benefits - scope/garbage collection and the content of a
C_Object is visible in the debugger. Those are "bloody mavhelous".

"you're tossing blocks of code at the end of the thread of control over
there for one-off execution."
Excellent way to phrase it. And the emphasis is on "over there" because the
code executes in the context of the destination form.

"execute in form" similar to "execute on client"

"On Outside Call was always documented as being unreliable while CALL FORM
/ CALL WORKER guarantee delivery."
OOC worked well form me, as far as I know (emphasis on the "AFAIK").
I did have to tweak my original code to work in a Repeat loop, as you say,
Call form/Call worker will always get through so there's no need to jump
through hoops (loops) to make sure the message arrived.


"NTK's IPC channels easier" - agreed. I"m using an array-based derivative
of that approach (taken from ITK about 20 years ago) with a change in
2000-01 and that's it. Highly reliable and zero maintenance but it doesn't
allow me to get to a specific form…which is what's needed to get at the *
dialog. Very nice to have multiple active windows in a process but
disappointing that I couldn't get to it with a message.


"You mention that you're doing message routine. This can be pretty darn
impossible to trace or debug if there's nothing in the message about the
path that it has followed."
I only had to chase messages "down a rabbit hole" a few times over the
years. Two ways of reducing the odds of that happening - one of the
properties of a message will allow the message and its metadata to be
displayed added to arrays displayed in a grid. I needed that to debug some
code that had become very involved and the end result is that it helped
force me to rethink my approach.

The other technique that I've used it a bit dated now but was very helpful
before V11, back in the dark ages when "Find in design" was dreadfully
slow. That situation convinced me to use IP vars in the message. From
*MSGIP_Vars_Init*:

C_TEXT(<>MSG_InsertCarriageReturn)
<>MSG_InsertCarriageReturn:="<>MSG_InsertCarriageReturn"

 C_TEXT(<>MSG_ProposalIsLocked)
<>MSG_ProposalIsLocked:="Proposals_is_Locked"

 C_TEXT(<>MSG_BringToFront)
<>MSG_BringToFront:="<>MSG_BringToFront"

C_TEXT(<>MSG_Close)
<>MSG_Close:="<>MSG_Close"

C_TEXT(<>PROC_Activated)
<>PROC_Activated:="<>PROC_Activated"


From On Outside call:
Repeat

C_LONGINT($msgHandle_L)
$msgHandle_L:=MSGIP_Message_Get (Current process)

C_TEXT($msg_T)
$msg_T:=MSGIP_TextMessage_Get ($msgHandle_L;False)

Case of
: ($msg_T=<>MSG_BringToFront)
PROC_ResumeAndBringToFront (Current process)

: ($msg_T=<>MSG_Close)
CANCEL
End case

MSGIP_Message_Clear ($msgHandle_L)

Until (MSGIP_MessageCount_Get (Current process)=0)


To your point about the provenance of the message, another significant
argument for an object without which it would be gruesome to try to add
that sort of data to…a BLOB?! No interest in the level of mental gymnastics…

Time to have a looksee here - http://forums.4d.fr/Post/EN/
19129127/1/19129128


--
Douglas von Roeder
949-336-2902

On Fri, Mar 17, 2017 at 2:18 PM, David Adams via 4D_Tech <
[hidden email]> wrote:

> > Interesting approach - thank you for posting that.
>
> DvR: You, of all people, will *love* this approach.
>
> > Lacking "callers" and C_Object, I've been using On outside call +
> > ObjectTools + IP messaging based on the ITK message queuing system.
>
> Once you have access to V16, you may find:
>
> * You like C_OBJECT because it's very fast and native. But it won't do
> everything that ObjectTools does.
>
> * You may still want to use IPC channels from NTK. They're traditional
> messages, easily support a wider range of messaging patterns, and can be
> used to-from anywhere.
>
> * CALL FORM/CALL WORKER are great! You'll love them. On Outside Call was
> always documented as being unreliable while CALL FORM / CALL WORKER
> guarantee delivery. (Unless you kill a worker, kill a process, kill 4D, or
> crash. But, hey, that's pretty reasonable for a lot of situations.)
>
> > I'm not sure if this is germane to Call form/worker but I include a
> "reply to ID"
> > in the message that's sent.
>
> Yes, that can be entirely relevant. These 'calls' aren't a channel, you're
> tossing blocks of code at the end of the thread of control over there for
> one-off execution. There is no return message. You can send along callback
> details if, for example, you need a result. There are times when you'll
> find NTK's IPC channels easier. And, yes, message discipline is _super_
> beneficial. You mention that you're doing message routine. This can be
> pretty darn impossible to trace or debug if there's nothing in the message
> about the path that it has followed.
>
> Tip: I've found it helpful to define a 'recipient' object as a specific
> type. This can be the recipient of a CALL FORM/CALL WORKER message or the
> callback details when you want a result, error, or confirmation message
> returned. By treating this as a custom data type, it's easy to have a
> single method for creating recipients and for validating them. "Validating"
> matters if you, for example, want to be sure that method names exist and
> that window refs are valid.
>
> > My projects are just moving to 15.x now so Call worker/call form are
> still
> > a bit out of reach for me but I'm glad to see that these have been added
> to
> > the language. They're a natural outgrowth of OOC, Call subform container,
> > etc., and we *finally* have a way to communicate with those windows
> opened
> > in the asterisk.
>
> Yeah, you'll love it. Given our existing framework, you'll feel like some
> things are missing - so keep NTK around. Also, vote for a native WebSockets
> implementation. This would be an *amazingly* great addition to 4D. You
> could have a persistent, bi-directional, point-to-point pipe between
> processes on one machine or different machines. Game changer.
>
> WebSocket protocol on 4D webserver
> http://forums.4d.fr/Post/EN/19129127/1/19129128
> **********************************************************************
> 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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
David:

Just read the feature request thread for WebSockets and I'm pretty certain
I voted for it (clicked 4 stars on the first message in the thread).

WebSocket fits well into the concepts of Call worker/form in that it's
providing developers with more granular connections and, hence more
granular control, over how data is requested and supplied. That would be a
very welcome addition to the 4D toolset.


--
Douglas von Roeder
949-336-2902

On Fri, Mar 17, 2017 at 3:02 PM, Douglas von Roeder <[hidden email]>
wrote:

> David:
>
> I'll read up on the web sockets - when I first saw that I misread it for
> "WebObjects". A cold chill ensued.
>
> C_Object is a great addition to the language. Agree that it doesn't do
> everything that OT does but that why we have wrapper routines. I've
> extended Cannon's OBJ_Module with OBJ_SetArray_Text/Long/Real and a few
> other array commands and I can get a lot done with C_Object that I'm doing
> in OT. The biggest benefits - scope/garbage collection and the content of a
> C_Object is visible in the debugger. Those are "bloody mavhelous".
>
> "you're tossing blocks of code at the end of the thread of control over
> there for one-off execution."
> Excellent way to phrase it. And the emphasis is on "over there" because
> the code executes in the context of the destination form.
>
> "execute in form" similar to "execute on client"
>
> "On Outside Call was always documented as being unreliable while CALL
> FORM / CALL WORKER guarantee delivery."
> OOC worked well form me, as far as I know (emphasis on the "AFAIK").
> I did have to tweak my original code to work in a Repeat loop, as you say,
> Call form/Call worker will always get through so there's no need to jump
> through hoops (loops) to make sure the message arrived.
>
>
> "NTK's IPC channels easier" - agreed. I"m using an array-based derivative
> of that approach (taken from ITK about 20 years ago) with a change in
> 2000-01 and that's it. Highly reliable and zero maintenance but it doesn't
> allow me to get to a specific form…which is what's needed to get at the *
> dialog. Very nice to have multiple active windows in a process but
> disappointing that I couldn't get to it with a message.
>
>
> "You mention that you're doing message routine. This can be pretty darn
> impossible to trace or debug if there's nothing in the message about the
> path that it has followed."
> I only had to chase messages "down a rabbit hole" a few times over the
> years. Two ways of reducing the odds of that happening - one of the
> properties of a message will allow the message and its metadata to be
> displayed added to arrays displayed in a grid. I needed that to debug some
> code that had become very involved and the end result is that it helped
> force me to rethink my approach.
>
> The other technique that I've used it a bit dated now but was very helpful
> before V11, back in the dark ages when "Find in design" was dreadfully
> slow. That situation convinced me to use IP vars in the message. From
> *MSGIP_Vars_Init*:
>
> C_TEXT(<>MSG_InsertCarriageReturn)
> <>MSG_InsertCarriageReturn:="<>MSG_InsertCarriageReturn"
>
>  C_TEXT(<>MSG_ProposalIsLocked)
> <>MSG_ProposalIsLocked:="Proposals_is_Locked"
>
>  C_TEXT(<>MSG_BringToFront)
> <>MSG_BringToFront:="<>MSG_BringToFront"
>
> C_TEXT(<>MSG_Close)
> <>MSG_Close:="<>MSG_Close"
>
> C_TEXT(<>PROC_Activated)
> <>PROC_Activated:="<>PROC_Activated"
>
>
> From On Outside call:
> Repeat
>
> C_LONGINT($msgHandle_L)
> $msgHandle_L:=MSGIP_Message_Get (Current process)
>
> C_TEXT($msg_T)
> $msg_T:=MSGIP_TextMessage_Get ($msgHandle_L;False)
>
> Case of
> : ($msg_T=<>MSG_BringToFront)
> PROC_ResumeAndBringToFront (Current process)
>
> : ($msg_T=<>MSG_Close)
> CANCEL
> End case
>
> MSGIP_Message_Clear ($msgHandle_L)
>
> Until (MSGIP_MessageCount_Get (Current process)=0)
>
>
> To your point about the provenance of the message, another significant
> argument for an object without which it would be gruesome to try to add
> that sort of data to…a BLOB?! No interest in the level of mental gymnastics…
>
> Time to have a looksee here - http://forums.4d.fr/Post/EN/
> 19129127/1/19129128
>
>
> --
> Douglas von Roeder
> 949-336-2902 <(949)%20336-2902>
>
> On Fri, Mar 17, 2017 at 2:18 PM, David Adams via 4D_Tech <
> [hidden email]> wrote:
>
>> > Interesting approach - thank you for posting that.
>>
>> DvR: You, of all people, will *love* this approach.
>>
>> > Lacking "callers" and C_Object, I've been using On outside call +
>> > ObjectTools + IP messaging based on the ITK message queuing system.
>>
>> Once you have access to V16, you may find:
>>
>> * You like C_OBJECT because it's very fast and native. But it won't do
>> everything that ObjectTools does.
>>
>> * You may still want to use IPC channels from NTK. They're traditional
>> messages, easily support a wider range of messaging patterns, and can be
>> used to-from anywhere.
>>
>> * CALL FORM/CALL WORKER are great! You'll love them. On Outside Call was
>> always documented as being unreliable while CALL FORM / CALL WORKER
>> guarantee delivery. (Unless you kill a worker, kill a process, kill 4D, or
>> crash. But, hey, that's pretty reasonable for a lot of situations.)
>>
>> > I'm not sure if this is germane to Call form/worker but I include a
>> "reply to ID"
>> > in the message that's sent.
>>
>> Yes, that can be entirely relevant. These 'calls' aren't a channel, you're
>> tossing blocks of code at the end of the thread of control over there for
>> one-off execution. There is no return message. You can send along callback
>> details if, for example, you need a result. There are times when you'll
>> find NTK's IPC channels easier. And, yes, message discipline is _super_
>> beneficial. You mention that you're doing message routine. This can be
>> pretty darn impossible to trace or debug if there's nothing in the message
>> about the path that it has followed.
>>
>> Tip: I've found it helpful to define a 'recipient' object as a specific
>> type. This can be the recipient of a CALL FORM/CALL WORKER message or the
>> callback details when you want a result, error, or confirmation message
>> returned. By treating this as a custom data type, it's easy to have a
>> single method for creating recipients and for validating them.
>> "Validating"
>> matters if you, for example, want to be sure that method names exist and
>> that window refs are valid.
>>
>> > My projects are just moving to 15.x now so Call worker/call form are
>> still
>> > a bit out of reach for me but I'm glad to see that these have been added
>> to
>> > the language. They're a natural outgrowth of OOC, Call subform
>> container,
>> > etc., and we *finally* have a way to communicate with those windows
>> opened
>> > in the asterisk.
>>
>> Yeah, you'll love it. Given our existing framework, you'll feel like some
>> things are missing - so keep NTK around. Also, vote for a native
>> WebSockets
>> implementation. This would be an *amazingly* great addition to 4D. You
>> could have a persistent, bi-directional, point-to-point pipe between
>> processes on one machine or different machines. Game changer.
>>
>> WebSocket protocol on 4D webserver
>> http://forums.4d.fr/Post/EN/19129127/1/19129128
>> **********************************************************************
>> 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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
On Sat, Mar 18, 2017 at 12:01 PM, Douglas von Roeder via 4D_Tech <
[hidden email]> wrote:

> David:
>
> Just read the feature request thread for WebSockets and I'm pretty certain
> I voted for it (clicked 4 stars on the first message in the thread).
>

Thanks! Not my feature request, but, dang, one of my favorites this year.
That and Cannon's request for an implicit C_OBJECT store for forms and so
on. That would also be pretty darn great for different reasons.


> WebSocket fits well into the concepts of Call worker/form in that it's
> providing developers with more granular connections and, hence more
> granular control, over how data is requested and supplied. That would be a
> very welcome addition to the 4D toolset.
>

Yeah, 'game changer' isn't an overstatement. A WebSocket is a reasonably
easy-to-use, dedicated two-way communications pipe between two processes.
And "processes", in this case, can mean a Web browser. So, you get a really
platform agnostic way of hooking 4D up to...well...anything that supports
WebSockets. Very, very nice idea. It doesn't do everything - but it fills
in a big gap. WebSockets also very neatly leverage a lot of existing HTTP
gunk (like for security), they don't require moderation by a dedicated Web
server. That's super flexible...and efficient. Imagine if you could spin up
a worker that's dedicated to a 4D process on a remote stand-alone, or a
remote client connected to a *different* 4D server, or connected to an
entirely different program in some completely unrelated language you've
never heard of, or connected to a Web browser. Persistently connected.
Bi-directional. The mind is blown.

For anyone that's interested in message-oriented architectures and/or
distributed computing setups (read: anyone working on a network),
WebSockets would real make 4D something like 4D^ 16D?
**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
In reply to this post by 4D Tech mailing list
On Mar 16, 2017, at 10:28 PM, David Adams via 4D_Tech <[hidden email]> wrote:
>
>  That's not what 4D's "messages" are, they're commands. In fact, the
> best names for the new commands are probably these:
>
> EXECUTE METHOD IN WINDOW
> EXECUTE METHOD IN WORKER

I was looking forward to finally having something better than CALL PROCESS available, but it is disappointing to see the level of coupling required to utilize the new commands. Something more similar to Cocoa’s NotificationCenter or javascript custom events would have been far more preferable.

If you use a string literal for the method name, does the compiler check that the method exists? It would be nice if the tokenized method name could be used; parenthesis could be required to also allow using the return value of a method as the parameter value. (This would be nice for any command that takes a method name, like New Process.)

Since using these will require code to be in project methods instead of object/form methods (I hate the invisibility of object methods, but also hate the pollution of the single namespace with thousands of tiny code snippets relevant to a single item), is there any general recommendation on project method organization? I have not been able to get project method folders to work myself. I’m also not sure if it’s even desirable to have project method folders, considering that there is only a single global namespace maybe it is better to have the hundreds to thousands of project methods in a single list?  

Is there some sort of “quick open” functionality for project methods that I haven’t found yet? Especially with all methods sharing the same list, if I’ve opened a form method type-ahead is useless until I’ve closed the form methods “folder”. Perhaps something like the 4DPop Commands list, but for opening project methods?

Jim Crate

**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
On Tue, Mar 21, 2017 at 4:45 AM, James Crate via 4D_Tech <
[hidden email]> wrote:

Hey Jim, it's good to have you chiming in.

> I was looking forward to finally having something better than CALL PROCESS
> available, but it is disappointing to see the level of coupling required
to
> utilize the new commands. Something more similar to Cocoa’s
NotificationCenter
> or javascript custom events would have been far more preferable.

You know how to pack a lot into a paragraph ;-) I haven't used Cocoa's
NotificationCenter to I looked it up. It looks like it implements
Publish/Subscribe and Observer. No, 4D's new commands do nothing like that.
The 'messages' aren't messages and the definitely aren't events. They're
blocks of code appended to the end of an existing thread of execution.
Arguably, it's meaningless to even talk about a 'queue' since we can't see
it, size it, or control it. (From inside of 4D, it makes sense to talk of a
queue - but as a 4D programmer? We have zero queue-like properties
available.)

In any case, you can use the new tools to write a publish-subscribe system
pretty nicely. (I've been doing this recently.) In fact, you can implement
publish-subscribe pretty well in 4D V14+ using its C_OBJECT data structure.
Peter Hay, Cannon Smith, Welsh Harris and other all seem to be pursuing
variations on Publish/Subscribe and/or MVVC.  Here's a relevant feature
request that needs your vote:

Automatically Associate C_Object With Form Objects (and the Window)
http://forums.4d.fr/Post/EN/19051683/1/19051684

If you don't know how to vote, it seems to be that you click on the 'rate'
stars at the top of the first post. From Tim Penner:

Tech Tip: How to vote for a feature request
http://kb.4d.com/assetid=76726

With the new commands, we definitely get some new options. If you're
comparing them to a full-on customizable event/event-injection framework,
you'll be disappointed. But if you take the new commands for what they are,
they're pretty great. As far as the degree of coupling, it's kind of up to
you to a degree. It's going to be simple for people to code things with
pathological coupling and it's also not hard to build very loose coupling.
For those of you following along at home that consider yourself "folk
programmers", "coupling" is the term for how different bits of a system are
connected. That can be different methods, different pieces of software
connecting over the network, whatever. "Tight" coupling is "bad" because it
means a change in one area requires or causes change in another. In a
"loosely" coupled system, whole sections of a system can be replaced or
rewritten without the rest of the world knowing a thing about it. CALL FORM
is kind of a good example here. Some off-the-top-of-my-head illustrative
code:

CALL FORM(DashboardWindow;"UpdateTickerText";->StatusTicker;"3 packages
received at 1:30 PM")

So, some bit of code pushes this code over for execution. It says "run the
UpdateTickerText method in the DashboardWindow. And tell UpdateTickerText
to change text of the variable StatusTicker to read or include the text "3
packages received at 1:30 PM!". While there are some situations that
justify this approach (testing, quick-and-dirty-demo...that's all I've
got), it's *tightly coupled.* The code that sends the command to the
dashboard has to know a lot about the dashboard. For example, the name of
the display variable. What if you want to change that variable? What if you
want to use an object name and not use a variable? You break the outside
world. So

CALL FORM(DashboardWindow;"HandleNotification";"3 packages received at 1:30
PM")

The "HandleNotification" method takes care of dealing with the data.
Doesn't look very different, but this kind of approach can be very
different. Taking things further, think about the code that's sending the
notifications to the dashboard. Sounds handy having a stream of
notifications about stuff that's happening. It might be nice to
-- Log these to a disk file, SQL database, or 4D
-- Update a Web page with some sort of timeline showing activity
-- Forward specific events to someone for handling - like if there's
spillage or something

So, a stream of events/notifications might have a lot of uses. But you've
got a 1:1 binding between the 'send notification' code and the dashboard
code. That's where a publish-subscribe system comes into play. With such a
system, the notification code publishes a service (you could call it
something else.) Something like this:

PublishService("WarehouseUpdates":"Receive real-time notifications of
important warehouse activities.")
Now the DashboardWindow, LogWorker, WebUpdater, etc. need to do this:

SubscribeToService("WarehouseUpdates";DashboardWindow;"Dashboard_HandleWarehouse")
SubscribeToService("WarehouseUpdates";LogWorker;"Log_HandleNotification")
SubscribeToService("WarehouseUpdates";WebUpdater;"WebUpdater_HandleWarehouse")
Something like that. When an event happens at the warehouse, you would call
something like

Warehouse_SendNotification (Message)
Notifications_Send("Warehouse";Message")
Notifications_GetSubscriptionList("Warehouse")
For($i;1;subscribers)
$target:=subscriber.identifier
$method:=subscriber.method
CALL FORM/WORKER (target;$method;$message)
End for
So, the same message (notification text, in this case) is sent to

Dashboard_HandleWarehouse
Log_HandleNotification
WebUpdater_HandleWarehouse
This is loosely coupled:

* The Warehouse module knows nothing about the subscribers. It doesn't even
know if there are any. There could be 0, there could be 12. It makes no
difference. Warehouse delegates notification and subscription management to
the Notification module. Notification, for its part, knows nothing about
the content, source, or target for the messages. All it knows how to do is
move a message from one place to another. To do this, it manages the
subscription list. And on the recipient side, it doesn't need to know
anything about notifications (apart from how to subscribe/unsubscribe) and
doesn't need to know anything about Warehouse, other than how to interpret
the notifications.

So, no, none of that's written into 4D out of the box but it is doable. My
own version is a late alpha right now. (Adding more test code for the
calls...which is hard to do...then adding the last tranche of
functionality.) For the record, I send around C_OBJECT messages in $1 and
that's it. It makes the system much more like a message queue or event
notification dispatcher. It's cool that you can call method parameters
directly with CALL FORM and CALl WORKER...but for a more loosely coupled
system, it's easier to pack that stuff into a generalized parameter. The
cost is that the parameters are opaque and you've got to do more custom
type/value/range checking yourself.

> If you use a string literal for the method name, does the compiler check
that
> the method exists? It would be nice if the tokenized method name could be
> used; parenthesis could be required to also allow using the return value
of a
> method as the parameter value. (This would be nice for any command that
takes
> a method name, like New Process.)

Yeah, sadly, no :( Another feature request that really needs some love:

Compiler/Typing Improvements: Detect some runtime errors in advance
http://forums.4d.fr/Post/EN/19107688/1/19107689

Several of us have resorted to writing custom code parsers to add this
test, check parameter lists, etc. Not a reasonable amount of work. 4D
really needs to add more checks into the compiler.

> Since using these will require code to be in project methods instead of
> object/form methods (I hate the invisibility of object methods, but also
hate
> the pollution of the single namespace with thousands of tiny code snippets
> relevant to a single item),

...hence the common practice in 4D of having ginormous 'handler' methods
with a fat case statement for different things. Sigh. In the case of forms,
it's not necessarily the worst approach available in 4D. But, ugh.

Oh, and speaking of namespaces - we need more than 31 characters for names,
largely because it's hard to avoid burning through a lot of characters to
implement pseudo-namespaces. Here's another feature request...this one
seems to have some momentum, but more votes can't hurt:

Raise the 31 character name limit on methods
http://forums.4d.fr/Post/EN/18946884/1/18946885

> is there any general recommendation on project
> method organization? I have not been able to get project method folders to
> work myself. I’m also not sure if it’s even desirable to have project
method
> folders, considering that there is only a single global namespace maybe
it is
> better to have the hundreds to thousands of project methods in a single
list?

! I use Explorer folders for everything. It makes it way easier to
navigate. They're hardly the ultimate feature, but they help me a lot. I
don't know about retrofitting them into an existing project with thousands
of methods. In my big code bases, I have custom screens for searching on
methods by name, attributes, etc. Between the commands to get process names
and the automatic option to open a method in Design, you can do a lot. Find
in Design is okay too, but it doesn't always do what you need and doesn't
let you save all of the results. (You can drag the results to a method and
you'll get a top-level summary.)

> Is there some sort of “quick open” functionality for project methods that
I
> haven’t found yet?

Yes! Great feature:

METHOD OPEN PATH
http://doc.4d.com/4Dv16/4D/16/METHOD-OPEN-PATH.301-3037152.en.html
**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

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

> On Mar 20, 2017, at 12:45 PM, James Crate via 4D_Tech <[hidden email]> wrote:
>
>  It would be nice if the tokenized method name could be used;

We need this in a lot of places. I think it could be as simple as a "Method name" command that takes the tokenized name and returns the string.

Feature request here:

http://forums.4d.fr/Post/EN/17984703/1/17984704

> Since using these will require code to be in project methods instead of object/form methods (I hate the invisibility of object methods, but also hate the pollution of the single namespace with thousands of tiny code snippets relevant to a single item), is there any general recommendation on project method organization?

For automated form testing purposes, I'm thinking about writing some code that generates one method with a giant case statement with all of the object statement snippets. This way you only add one method per form and don't have to change the way you write your code for forms. Just an idea at this point, but seems like it would be simple to do.

> Especially with all methods sharing the same list, if I’ve opened a form method type-ahead is useless until I’ve closed the form methods “folder”.

Agree. I think it would help a lot if there was a setting to control type-ahead. Even with short prefixes, I can't always type the prefix plus underscore without 4D starting a new type-ahead search because I'm too slow after the underscore. Often ends up search, then scroll.

John DeSoi, Ph.D.

**********************************************************************
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: CALL FORM: Some notes on a command that's easy to misunderstand

4D Tech mailing list
In reply to this post by 4D Tech mailing list
>
> > Is there some sort of “quick open” functionality for project methods
> that I
> > haven’t found yet?
>
> Yes! Great feature:
>
> METHOD OPEN PATH
> http://doc.4d.com/4Dv16/4D/16/METHOD-OPEN-PATH.301-3037152.en.html
>

P.S.  I think that API Pack's version of this feature allows you to open at
a specific line number, which is a help. I lean on open a method features a
lot from windows such as these:

-- Any of my code builders, tweakers, or searches
-- Error log details where a method name is listed (most of my errors
record the method name)
-- Test configuration records that invoke a method

Handy.
**********************************************************************
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
|

AW: CALL FORM: Some notes on a command that's easy to misunderstand

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

Regarding check of method name as string, e.g. for New Process: you could check the name using METHOD GET NAMES. It's not perfect, but better than nothing.

My recommendation regarding project method organization: prefix your method names (and form names) for each "module" with 3 or 4 letters. I like the feature of the explorer home section where you can organize your items in folders. Especially I like to keep forms and associated code (project methods) in one single folder. I use Object and Form methods only to pass the event to a project method, e.g.

Case of

:(Form event=on clicked)

MyEventHandlingMethod(Object get name(object current);"OnClicked")

End case

I prefer passing the event as a string. This gives me the freedom to create my own events, such as "Update", "Disable" etc.

Moving code away from object methods to project methods does not lead to more but to less (and better organized) code, at least this is my experience. Important is to have a clear concept of how to organize the code around the form.

I also try to "externalize" parts of my projects to components. Components have their own namespace (except for shared methods).

IMO there is nothing wrong with the name "CALL FORM". It calls a form, executes a method and this method has access to the objects of the called form.

Olivier

-----Ursprüngliche Nachricht-----
Von: 4D_Tech [mailto:[hidden email]] Im Auftrag von James Crate via 4D_Tech
Gesendet: Montag, 20. März 2017 18:45
An: 4D iNug Technical <[hidden email]>
Cc: James Crate <[hidden email]>
Betreff: Re: CALL FORM: Some notes on a command that's easy to misunderstand

On Mar 16, 2017, at 10:28 PM, David Adams via 4D_Tech <[hidden email]> wrote:
>
>  That's not what 4D's "messages" are, they're commands. In fact, the
> best names for the new commands are probably these:
>
> EXECUTE METHOD IN WINDOW
> EXECUTE METHOD IN WORKER

I was looking forward to finally having something better than CALL PROCESS available, but it is disappointing to see the level of coupling required to utilize the new commands. Something more similar to Cocoa’s NotificationCenter or javascript custom events would have been far more preferable.

If you use a string literal for the method name, does the compiler check that the method exists? It would be nice if the tokenized method name could be used; parenthesis could be required to also allow using the return value of a method as the parameter value. (This would be nice for any command that takes a method name, like New Process.)

Since using these will require code to be in project methods instead of object/form methods (I hate the invisibility of object methods, but also hate the pollution of the single namespace with thousands of tiny code snippets relevant to a single item), is there any general recommendation on project method organization? I have not been able to get project method folders to work myself. I’m also not sure if it’s even desirable to have project method folders, considering that there is only a single global namespace maybe it is better to have the hundreds to thousands of project methods in a single list?  

Is there some sort of “quick open” functionality for project methods that I haven’t found yet? Especially with all methods sharing the same list, if I’ve opened a form method type-ahead is useless until I’ve closed the form methods “folder”. Perhaps something like the 4DPop Commands list, but for opening project methods?

**********************************************************************
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]
**********************************************************************