Menu

How to invoke a user-defined function?

Anonymous
2022-07-16
2022-07-20
  • Anonymous

    Anonymous - 2022-07-16

    I've been trying to write a user-defined function, but I can't figure out how to call it directly without using DISPLAY or MOVE. The COBOL standard says that it should be possible but it's not working.

    IDENTIFICATION DIVISION.
      FUNCTION-ID. USERFUN.
    DATA DIVISION.
      LINKAGE SECTION.
        01 LS-VAL PIC 9(1).
    PROCEDURE DIVISION RETURNING LS-VAL.
        DISPLAY "Hello, World!".
        MOVE 5 TO LS-VAL
        GOBACK.
    END FUNCTION USERFUN.
    
    IDENTIFICATION DIVISION.
      PROGRAM-ID. HELLO.
    ENVIRONMENT DIVISION.
      CONFIGURATION SECTION.
        REPOSITORY. FUNCTION USERFUN.
    PROCEDURE DIVISION.
      FUNCTION USERFUN.
    STOP RUN.
    

    This is the code that I'm trying to make work, it's just a program that calls a function and the function displays "Hello, World!" and returns 5. What am I doing wrong, I'm getting a "syntax error, unexpected user function name"

     
  • Simon Sobisch

    Simon Sobisch - 2022-07-16

    The COBOL standard says that it should be possible but it's not working.

    How do you come to this conclusion?

    With the most current draft (actually the DIS) we have:

    8.4.2.2.3 Function Identifiers, general rules

    A function-identifier references a temporary data item whose value is determined when the function is referenced at runtime.

    Given that it is similar to just write PROCEDURE DIVISION. YOUR-DATA-NAME. , no?

    I can't figure out how to call it directly without using DISPLAY or MOVE.

    For calling programs you use the CALL statement, for invoking methods (not yet supported in GnuCOBOL and many other COBOL environments) you use the INVOKE statement, for invoking any function you reference it in place of a data-item, because that is what a function "is".

    What you want in the procedure division is a statement, not a data item.
    The following would work: DISPLAY YOUR-DATA-NAME.or MOVE YOUR-DATA-NAME TO VAR. and therefore DISPLAY YOUR-FUNCTION. and MOVE YOUR-FUNCTION TO RETURN-VAR. will, too.

    Rule of thumb: programs and methods do something, they may output their results with io (screen, file, db), parameters per default are passed BY REFERENCE as changing them is one of the common things done. They may be very complex and invoking them may take quite some time.
    Functions (both intrinsic and user-defined) use the parameters passed them (which are passed by default BY VALUE) to calculate something or give you a specific representation based on the input parameters; they are commonly returning fast. While no statement is explicit forbidden io statements of any type are commonly not to be used in there.

    Question, mostly @ktsnowy but also in general: Can you get to this conclusion when reading the Programmer's Guide
    @vcoen @cutlergl Do you think there may be some introductory paragraph making this explicit by (a better version of) an explanation like the one above?

     
  • Anonymous

    Anonymous - 2022-07-16

    A user-defined function is invoked by specifying a function identifier as described in 8.4.2.2, Function-identifier.

    A function-identifier references the unique data item that results from the evaluation of a function.

    The current DIS then gives this general format that I'm sending as an Attachment.

    Function-prototype-name-1 shall be the user-function-name of the containing function definition or a function prototype specified in the REPOSITORY paragraph.

    I might be reading it wrong though, but after saying this it then gives an example of using the intrinsic MAX and RANDOM functions like this so I thought that user-defined functions could be invoked in the same way by defining them in the REPOSITORY paragraph.

    The standard seems to give the impression that it's possible.

     

    Last edit: Anonymous 2022-07-16
    • Simon Sobisch

      Simon Sobisch - 2022-07-16

      Any functions can be invoked directly - but any function results in a temporary data item and can therefore only be used where a data-item of the same category/class may be used.

       
      • Anonymous

        Anonymous - 2022-07-16

        So I would always need to MOVE the function name to a variable or DISPLAY it? MOVE will assign the return value to the variable and DISPLAY will display the return value, that makes sense.

        I got confused with the wording on the standard and thought that it was possible to use "FUNCTION FUNCNAME" alone in a line. Sorry about that.

        I was asking this because we're building a COBOL exercises track on Exercism and we'll have to come up with exercises to teach all of this.

         
        • Simon Sobisch

          Simon Sobisch - 2022-07-16

          MOVE will assign the return value to the variable and DISPLAY will display the return value, that makes sense.

          Yes. Depending on the context COMPUTE is a very reasonable statement there, too - but as noted: the main issue is the purpose of functions (they are not like user written functions in C, which more relate to a CALL).

          I got confused with the wording on the standard and thought that it was possible to use "FUNCTION FUNCNAME" alone in a line. Sorry about that.

          No problem, that's what this discussion board is for :-)

          I was asking this because we're building a COBOL exercises track on Exercism

          That's nice, keep it going!

           
          • Anonymous

            Anonymous - 2022-07-16

            they are not like user written functions in C, which more relate to a CALL

            So in the cases where I would want to CALL it instead of assigning to a variable, would you recomment writting another COBOL program in the same source file and then CALLing it instead of a user-defined function?

             
            • Simon Sobisch

              Simon Sobisch - 2022-07-16

              I'd recommend to have "modules" that should be used from several programs in a source file and compiled as module, loaded by CALL. You may also put multiple programs and/or functions into a single source file (while I personally prefer one for each if there is no reason for nesting) and also compile multiple sources into a library (using -b if you have multiple source files).
              You can also dynamically load a library by including at least one CALLable program in there and have it named identical to the library name - or use COB_PRE_LOAD to make it available (in which case you don't need a program in it either).

              I'm not sure I understand the question correctly: if I only want a single return (mostly but not limited to numbers) and commonly don't want the input parameters to be changed, I'd go for a function.
              This is especially true when I need that result to be completely temporarily, only used for an inline computation or another function or program invocation.

              Things where I'd personally recommend to prefer a program over a function: * if I see the need for any screen-io * has any io that is not pure logging or "fire and forget" (like sending to a message-que) * rather complex input parameters (a record that is not a "anonymous structure" [= filled in some utility program / other function only])

               
              • Anonymous

                Anonymous - 2022-07-17

                Hey just one more question, hope that's alright. Does the standard specify any methods of getting data from command line arguments? I can't seem to find anything on how to start a program and give it a file like this:
                ./cobprogram file.txt
                Or arguments like this:
                ./cobprogram -r --help

                 
                • Vincent (Bryan) Coen

                  From the Programming Guide (gnucob-a4.pdf):

                  10.2.4. Program Arguments
                  Regardless of the manner in which a main program is executed (i.e.
                  directly or via cobcrun),
                  any arguments specified to the program may be retrieved via any of the
                  following:

                  • ACCEPT FROM COMMAND-LINE (see [ACCEPT FROM COMMAND-LINE], page 239)
                  • PROCEDURE DIVISION CHAINING (see [PROCEDURE DIVISION CHAINING], page 222)

                  On 17/07/2022 01:30, KTSnowy wrote:

                  Hey just one more question, hope that's alright. Does the standard
                  specify any methods of getting data from command line arguments? I
                  can't seem to find anything on how to start a program and give it a
                  file like this:
                  |./cobprogram file.txt|
                  Or arguments like this:
                  |./cobprogram -r --help|

                   
                  • Anonymous

                    Anonymous - 2022-07-17

                    Issue is that PROCEDURE DIVISION CHAINING is not part of the standard, or at least I couldn't find it in there and the CHAINING keyword is not part of the reserved words list.

                    I'm trying to stay as close to standard COBOL as I can when teaching these exercises, to make it as compatible as possible with other dialects and compilers.

                    Is the ACCEPT FROM COMMAND-LINE part of the standard?

                    It mentions this in the ACCEPT keyword specification:

                    Mnemonic-name-1 shall be specified in the SPECIAL-NAMES paragraph of the environment division and shall be associated with an implementor-defined device-name that is identified in the operating environment as a hardware or software device capable of providing data to the program.

                    So this means that the COMMAND-LINE name has to be specified in the SPECIAL-NAMES paragragh with a device name? COMMAND-LINE itself doesn't seem to be a keyword in the standard.

                     
                    • Vincent (Bryan) Coen

                      CHAINING has been around since before COBOL70 - OK guessing about the
                      time period.

                      It is also IN the reserved lists.

                      I.e.,  :

                      CARD-PUNCH                      Yes (Context sensitive)
                      CH                              Yes
                      CHAIN                           No
                      CHAINING                        Yes
                      CHANGED                         Yes (Context sensitive)
                      CHARACTER                       Yes
                      CHARACTERS                      Yes
                      CHECK-BOX                       Yes (Context sensitive)

                      Try it by running cobc --list-reserved | grep CH

                      V.

                      Mod edit for some reply-to

                       

                      Last edit: Brian Tiffin 2022-07-20
                      • Anonymous

                        Anonymous - 2022-07-17

                        Hey Vincent, I know that the CHAINING keyword is part of gnuCOBOL, but it is NOT part of the COBOL standard's reserved keywords.

                        This means that the CHAINING keyword is a non-standard extension, and that there's no guarantee that it's going to work outside of gnuCOBOL.

                        The CHAINING keyword for example is not present in Enterprise COBOL's reserved words list.

                        When teaching COBOL itself it's a little hard to justify using non-standard features that might not work on other COBOL compilers, a student for example might try to use CHAINING on IBM COBOL on z/OS to get command line parameters, find that it doesn't work and get confused as to why.

                        We're trying to stay as close as possible to Standard COBOL when teaching it to avoid these kind of situations where a feature doesn't work on other compilers, and since COBOL is a standardized language this should be the default anyways.

                         
                        • Vincent (Bryan) Coen

                          The world of Cobol does NOT rest with IBM and zOS.

                          In my copy of the quick Cobol pocket Guide CHAINING is therre and that
                          is dated 86-93  where is is for the Workbench Cobol compiler v3.3/4 for
                          DOS, Windows ans OS/2.

                          It is not in ANSI COBOL from the late 60's but there again very little
                          is - it was a poor compiler that for most programmers waited for the
                          later OS/VS COBOL (2). that came out a year or two later one year for
                          the Beta version.

                          That said m/f cobol did not really require the use of chaining by the
                          nature of operations for mainframes but many do have processes to pass
                          on JCL params to a program and the methods vary depending on the
                          compiler including ASNI Cobol for MVS 3.8J.

                          CHAINING is a micro usage feature so MF, Accu , Reallia etc are more
                          likey to have them as against any mainframe including IBM, ICL,
                          Burrough's, Honeywell etc.

                          Spelling mistakes allowed as its 02:30 now.

                          Vince

                          Mod edit for some reply-to

                           

                          Last edit: Brian Tiffin 2022-07-20
                          • Anonymous

                            Anonymous - 2022-07-18

                            The world of Cobol does NOT rest with IBM and zOS.

                            That's not what I was trying to say and I'm sorry if that's how my comment sounded like.

                            But again CHAINING is not part of the COBOL standard, if you read the latest COBOL 2022 DIS or the 2014 standard you might notice that CHAINING is not there at all.

                            COBOL is a standardized language and when teaching COBOL the language it's better to stick to the standard than a specific compiler due to these issues.

                            We're trying to teach COBOL the language, not a specific COBOL compiler, so using CHAINING is just not possible because it's not in the standard.

                             

                            Last edit: Anonymous 2022-07-18
                        • Simon Sobisch

                          Simon Sobisch - 2022-07-18

                          Getting parameters from the environment is - per topic - dependent on the environment, as it is different how COBOL programms are started.
                          For IBM you'd likely use PARM, an extension from IBM, pending in GnuCOBOL (available in less COBOL compilers for PC than CHAINING).

                          The only thing that "kind of" sticks to the standard directly but isn't in IBM is ACCEPT FROM COMMAND LINE.

                          For your class I'd teach that system dependent stuff should always be wrapped in a separate program, so possibly:
                          starter (stub that only reads parameters, converts to target types, then starts the program) + program (using best-fit USAGE and PICTURE) + possibly parameter validation/conversion in a separate program started by the starter (biggest benefit in the separation is easy unit testing).

                           
                          • Anonymous

                            Anonymous - 2022-07-18

                            starter (stub that only reads parameters, converts to target types, then starts the program) + program (using best-fit USAGE and PICTURE) + possibly parameter validation/conversion in a separate program started by the starter (biggest benefit in the separation is easy unit testing).

                            This is a really good idea, I'll try doing this for the class, thank you.

                            I also found out that the devices available are always compiler dependent, and after reading a little bit I found that gnuCOBOL also has a CONSOLE device that I could use from ACCEPT.

                            Is there any differences between the ACCEPT FROM COMMAND-LINE and ACCEPT FROM CONSOLE?

                             
                            • Simon Sobisch

                              Simon Sobisch - 2022-07-18

                              ACCEPT something FROM CONSOLE is reading from stdin
                              https://gnucobol.sourceforge.io/HTML/gnucobpg.html#ACCEPT-FROM-CONSOLE

                              ACCEPT something FROM COMMAND-LINE is reading the arguments as passed
                              by the starter (commonly a shell which may do wildcard translations), see

                              As an alternative to the complete arguments you can get the number of
                              arguments with ACCEPT nums FROM ARGUMENT-NUMBER and use a couple of
                              DISPLAY next-num UPON ARGUMENT-NUMBER + ACCEPT param FROM ARGUMENT-VALUE, the Programmer's Guide very likely has details on this,
                              too.

                              Note: If something is missing / seems strange: always use the current
                              PDF version from subversion, the HTML version is only regenerated and
                              re-uploaded from time to time (commonly short after a release).

                              If you are fine with a GnuCOBOL only way in a special starter (this may
                              be gcstart.cob as an optional exercise), then have a look at
                              CBL_GC_GETOPT, the manual has entries for it and we also have "complete
                              sample code" in the testsuite [1].

                              Simon

                               
            • Brian Tiffin

              Brian Tiffin - 2022-07-20

              Interjecting: Personal preference, which is almost always COBOL in the Small.

              Multiple program-id's per source file. As all-in as you can, without breaking (usually mythical) future re-use. Even programming in the middling, like cobweb-gtk, as all-in as is feasible. Support FUNCTIONs, support CALLables, all in.

              COBOL in the Large, completely different opinion on how much extra discipline and manifest management is required or recommended, where separation of concerns is far more important than convenience.

              Have good, make well,
              Blue

               

Anonymous
Anonymous

Add attachments
Cancel





Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.