ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

AS400 Memory and architecture for beginners

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • AS400 Memory and architecture for beginners

    Hello,

    I've never had a basic course on memory or architecture (in any language) and I find myself needing clarification on basic concepts relating to memory (allocation, usage, etc.) and architecture, preferably using AS400 as the base. Concepts such as the different types of memory allocations (static, dynamic, etc), the different types of memory (buffers, stack, heap, segments, cache), the size of the blocks of memory used in AS400, etc.

    I need to understand exactly where in the memory data is stored when a READ is done (what kind of memory), or when I write to a subfile, or when I want to use the key word RTNDTA on a DSPF. Why a subprocedure can "see" and use global variables but why the main program can't use the variables of a subprocedure (what mechanism prevents this?). When is memory allocated? When is it released? How does a variable identify which memory space to work on (for example, when a subprocedure has a local variable with the same name as a global variable, how does it know to work on the local variable instead of the global?).

    A basic course explaining the basics of memory and architecture in respect to AS400. Everytime I do a search, I only ever come across the concepts of memory pools. I'm not there yet!

    Thanks!
    Last edited by JustPassing; November 13, 2019, 03:37 AM.

  • #2
    Let's start with a course in the name of the system. It is "IBM i" - there have been no AS/400s for some 15 or 20 years. It is sadly a name that won't die.

    It would help to know why you need this knowledge. In IBM i terms - very little of it matters due to the way the system works. For example on IBM i _everything_ is memory. Terminals, disk drives, everything. The concept is known as single-level store and it a major architectural difference from other systems.

    Couple of relevant memory things.

    1) Program instructions are stored separately from data. There is only one copy of a given program in memory at a time and every user using that program has their own copy of the relevant data. It is this separation in part that prevents the system from being affected by many viruses and other exploits. You cannot change program instructions by writing over their memory from within a program. In fact due to a feature known to as tag bits, you can't even change an address pointer other than via special pointer instructions. A feature that keeps the system safe but can make it harder to port badly written C/C++ code to the box.

    2) From a program's perspective there is static memory and dynamic memory. Static is allocated to the program at startup - actually as noted at point 1 it is really allocated to the user but ... Dynamic is what is used for subprocedure variables and when a program specifically requests it (via %Alloc in RPG for example). Dynamic memory is allocated on the stack/heap and, in the case of subprocedures, released when the subprocedure returns control to its caller. The fact that a subprocedure can "see" global variables (i.e. this in static memory) but that main line instructions cannot "see" local variables is a convention enforced by the compiler and is normal in most languages.

    3) When you interact with files the way memory is used varies by language. The underlying OS handles them all the same but RPG has some unique aspects. In COBOL or C, when a read takes place (for example) the resulting data buffer is made available to the program. The program's field definitions are simply mapped to the buffer. In RPG that buffer is "hidden" and individual fields are moved from the buffer to their storage location. This happens because RPG has a concept of one-field-name-one-memory-location. In other words if a field called ACCNO exists in two files used by a program it is stored in a single location in the memory. If it contains the value 1234 and the value 2345 is read (from either file) then the value of ACCNO just changed.

    4) Subfile memory etc. is held by the OS (specifically I guess workstation data management) and is not accessible by the programmer - so we don't really care where it is.

    5) RTNDTA is just a feature that is not used that often. As the IBM manual explains it is most commonly used when program A reads from the display file and examines the data and determines that program B really needs to process it. Rather than A having to pass to B all the screen data RTNDTA allows A to call B which can then re-read the screen to get the data. Not sure why you are asking about this specific feature but ... I suspect that it originates from many, many years ago (maybe System 3 or S/34?) before there were program parameters.

    Other than the bits above re static and dynamic and separation of program and data memory there is really no need for a programmer on IBM i to ever worry about this stuff. that is why you don't find anything in internet searches. There are books and published papers on the technical implementation but to those of us who write programs for the box they are of purely academic interest.

    As I said - if you tell us WHY you want to know all these we may be able to help more.

    Comment


    • #3
      Hi, thanks for taking the time to explain to me. I assure you, if I want to understand more clearly these concepts, it's not for academic purposes but because not understanding it all clearly hinders my ability to be a competent developer. Not clearly understanding how it works means I'm prone to meet errors that I don't understand. It makes me less productive because I then have to search the internet, wading through tons of irrelevant results, before finding useful information. And if I have a coworker who asks me a question (especially one that has less experience than me), not being able to explain convincingly doesn't make me look competent.

      The questions I asked were just examples of issues that I didn't understand properly. I have an intuitive understanding of how memory works but there are much finer points that I cannot guess without understanding its implementation.

      For example, I had a problem last week. I wanted to pass some numeric DSPF fields (defined as zoned) to a subprocedure that took packed decimals as parameters. But last week, it keep telling me that the variables passed did not match the definitions of my subprocedure. But I've always passed parameters that way and I've never had a problem with it. These were in-out parameters so I could not just put CONST on them and I didn't want to have to use temporary variables just to get it to work, so I dug into it.

      It turns out, when programs are compiled, there's such a thing as an "internal format" that you can see in the cross-reference section of the spool generated, and that by default is PACKED for all numeric fields even if your fields are ZONED. What had happened is that I had put my DSPF fields into a DS and because of that, when I was compiling, these fields were being compiled with an internal format of ZONED instead of PACKED, explaining why I couldn't just pass them to my subprocedure as I had previously done in other programs.

      These are things that I cannot know and I lose a lot of time having to search it. And I still don't understand the concept of internal format or why putting the fields in DS make them ZONED or why numeric fields in DS should be ZONED instead of PACKED.

      Another example, just this week. We kept having "MCH3601 - Pointer not set for location referenced" error problems when calling RPG/400 or CLP programs from CLLE. When we'd change from CLLE to CLP, no problems. It turns out it's a "frequent issue" and has to do with how CLLE and RPG pass parameters. There's an explanation here https://archive.midrange.com/midrang.../msg00890.html and it talks about the "stack" and pointers (a concept I understand), but I don't know much about the concepts of "stacks" or the "heaps" or buffers or any of that. And I'd especially like to know where this person got his information from. Where do you find this information? What documentation explains it? How do you find out that data is being transferred from the stack to the storage location? I just don't understand it.

      That's why I need to understand these concepts, to understand how these things work clearly, why they were implemented the way they were. A lot of what you said cannot be guessed. The parts about memory being allocated to each user, for example, or the buffer being "hidden" and fields moved to their storage locations. Are those not things an IBM i developer should know? Having a clear idea how these things work certainly would be useful when we run into bugs or errors.

      I think I'm going to have to go more general and just look for a book on memory and architecture in general. I've found some but I would have preferred to find something relating more directly to IMB i and the Power Systems.

      Thanks anyway.

      Comment


      • #4
        A book on memory and architecture will not help you. The issues you raise arise primarily from your lack of knowledge of RPG and the way in which it works. As a secondary issue you need to gain understanding of ILE principles and IBM i in general. So what you need are good books on RPG and IBM i. Trust me - a book on memory architecture will not help you.

        Let's look at the examples you posted.

        "Internal format" for example. For historical reasons of efficiency, RPG has always defaulted numeric values to packed decimal. So it is normal for a (say) database field defined as zoned to be converted to packed internally to the program IF the programmer does not force it to do otherwise. For example - as you found - if you were to define a DS in your program based on a file's external definition (via the LikeRec or ExtName keywords) you find that the numeric field in question retains its zoned definition. RPG only switches it to packed when you don't tell it where in memory you want it to go. If you think back to what I said earlier about one-field-name-equals-one-memory-location then it makes sense that there has to be some default rule for what to do when the field types don't match. For example - I have a numeric field on a display file - that same field exists in a database as a packed value. But you can't write a packed value to a display - it would look like gibberish - so the compiler has to decide on a common format. Historically that format is packed for numerics.

        You say you could not use CONST because the field was I/O. But you could have used CONST on the input and have the called function RETURN a value. So that instead of coding:

        DoSomething( Field1 );

        You would be coding:

        Field1 = DoSomething( Field1 );

        That permits the use of const - end of your problem.

        Another option would be to change the way your prototype/procedure interface is defined. I'm guessing right now you have hard coded the parameter definition. But you could code it using the LIKE keyword which would make sure that the definitions matched. P.S. While that is usually OK for internal procedures it is not a good idea for external procedures (i.e. ones in Service Programs).

        In your CL example it is not a lack of understanding memory issues but rather a lack of understanding the way ILE handles parameters. You appear to have decided to use CALLPRC rather than CALL in your original CLLE for some reason (I'm making that assumption based on the "answer" that you found). Had you stuck with CALL you would not have had this problem. .


        How did you learn your RPG? If I knew that I'd know better where you were coming from. Also what other languages/platforms are you familiar with?

        Just to reiterate though - your problems are not with computer architecture and memory management - they are with RPG.

        Comment


        • #5
          The reason why I didn't change subprocedure to have CONST fields and just return a value is because I had two values to return. I imagine I could have tried returning a string containing both values or perhaps a DS, but it felt it would be the less understandable option for whoever were to modify my program later on. I resolved the issue by simply removing the DSPF fields from the DS.

          No, our CLLE was calling a command created based on a CLP that itself would call an RPG/400 program.

          While I certainly do need more knowledge in RPG, I also do think I need to understand memory better. Perhaps the two previous examples were not the most relevant. In the RTNDTA example I spoke of, we use it on DSPF where the DSPF fields have the same name as the file fields it reads from. The RTNDTA keyword allows us to read the file, display the DSPF, let the user make modifications, then reread the file without overwriting the modifications before updating.

          I'm still not sure I understand exactly what happens. Based on what I understand, when the user makes modifications, the modifications are stored in the input buffer. When we reread the file, only the fields in the storage area are overwritten. Because we have the RTNDTA keyword in effect, the system sends back the values that are in the input-buffer to the program, effectively overwriting the values in the storage area with the modifications before the update copies those values to the file. Is that how it should be understood?

          You see, it's completely memory-related. I didn't even understand that there was such a thing as an input-buffer until just recently. And to understand concepts like VALUE, CONST, or "parameter passing by reference", I had to understand basic concepts about memory. I also still don't quite understand issues relating to garbage characters that can appear in certain memory addresses, when you have a large character field, for example, but only pass a small string, or why sometimes using %addr(Var) = *null doesn't work because of garbage characters that appear in that address even though the parameter was not passed (I now only use %parms in subprocedures because %addr only works the first time I call a subprocedure. Afterwards, there are always garbage characters in the address of the parameter).

          I understand what you're saying. I DO need to learn more about RPG. But I just have so many questions relating to memory, like where is this data stored? In what type of memory? Why in the buffer and not in the "storage area"? Why in the stack and not in a buffer? If I do this, what data in what memory will be impacted by it? I really don't see it clearly. It certainly is not the only issue I have, but surely understanding memory better would be beneficial.

          Comment


          • #6
            You asked where people who have answered questions got their information. In my case, and I suspect this is true for most people, I got nearly all my knowledge through running into problems and finding the solutions, either by experimenting, or reading manuals, or googling, or asking someone else, or usually a combination.

            While you might feel like you're losing time when you run into things you don't understand, you're actually gaining time in the long run, because now you have more experience.

            Comment


            • #7
              Originally posted by JustPassing View Post
              I understand what you're saying. I DO need to learn more about RPG. But I just have so many questions relating to memory, like where is this data stored? In what type of memory? Why in the buffer and not in the "storage area"? Why in the stack and not in a buffer? If I do this, what data in what memory will be impacted by it? I really don't see it clearly. It certainly is not the only issue I have, but surely understanding memory better would be beneficial.
              Why does it matter? You can only access the data in the ways that RPG permits. Whether the data is "in the cloud" - or on a USB stick - or ... is irrelevant.

              Let me try again to give a simplified version to explain what happens and to differentiate by using BOLD between what you can "see" and therefore affect and what happens under the covers.

              A disk file is opened for input - in response the OS passes a pointer to RPG to the control block for the file.

              Your RPG code issues a READ.

              RPG runtime passes the control block back to the OS requesting data.

              The OS returns a pointer to the appropriate block of data (this would normally be a block of records) - this is what we would normally refer to as the "buffer"

              RPG runtime determines where the required record begins and extracts each field in turn from the record. Where in memory the field is stored was determined by the compiler at compile time and (other than if the field is in a DS) is an arbitrary location. In some cases numeric values may be converted to packed during this process. Something similar can happen with dates but let's not worry about that for now.

              Your program can now access the fields read.

              If a WRITE were done a similar process would be followed in reverse.


              OK - on to stack memory. Most RPG programmers neither know nor care about it. Some may realize that parameter passing on bound calls (i.e. procedure calls not program calls) is "different" to that used on program calls but they don't usually need to know that. On a bound call parameters are passed on the stack (that is a general computer concept and if you don't know it already that you can study via google). This is an over simplification but basically think of the stack as just that - a heap of stuff. Parameters can be passed by reference (the default) which means that a pointer to the data is placed on top of the stack, or by value which means that the actual data is placed on top of the stack. In the called routine, that data is the pulled off the stack and used to obtain the parameters. This mechanism is all hidden from the programmer and in fact there are certain types of data where it doesn't quite work this way - but it is unimportant because the programmer cannot make use of that information - he just determines how (reference or value) the parameter is passed.

              I'll respond to other points in different posts.

              Comment


              • #8
                Originally posted by JustPassing View Post
                The reason why I didn't change subprocedure to have CONST fields and just return a value is because I had two values to return. I imagine I could have tried returning a string containing both values or perhaps a DS, but it felt it would be the less understandable option for whoever were to modify my program later on. I resolved the issue by simply removing the DSPF fields from the DS.
                Returning a string with both values would be a really bad idea. Returning a DS would have been the appropriate alternative.

                Your other option was to fix the problem by either changing the called routine to accept packed numbers, or to have used a DS to control the data type of the parms so that they remained zoned.

                Comment


                • #9
                  Originally posted by JustPassing View Post
                  No, our CLLE was calling a command created based on a CLP that itself would call an RPG/400 program.
                  In that case the "answer" you quoted earlier had no bearing on your resolution. Something else was at play and without seeing the code I won't hazard a guess.

                  Comment


                  • #10
                    Originally posted by JustPassing View Post
                    While I certainly do need more knowledge in RPG, I also do think I need to understand memory better. Perhaps the two previous examples were not the most relevant. In the RTNDTA example I spoke of, we use it on DSPF where the DSPF fields have the same name as the file fields it reads from. The RTNDTA keyword allows us to read the file, display the DSPF, let the user make modifications, then reread the file without overwriting the modifications before updating.

                    I'm still not sure I understand exactly what happens. Based on what I understand, when the user makes modifications, the modifications are stored in the input buffer. When we reread the file, only the fields in the storage area are overwritten. Because we have the RTNDTA keyword in effect, the system sends back the values that are in the input-buffer to the program, effectively overwriting the values in the storage area with the modifications before the update copies those values to the file. Is that how it should be understood?
                    This seems a rather strange way of doing it - this sounds like an RPG III (i.e. RPG/400) technique. Normally you would read the file, display it to the user for changes, read the display file, validate the changes, and only rewrite the file if the validation passed. Perhaps this is to preserve display file content in the event of validation errors? Without seeing the code I can't guess.

                    When the display file is read, the fields are copied to what you call the storage area. If you were then to read a disk file with the same field names, that content would be overwritten. So if you want the display file changes then yes - you would have to use RTNDTA and re-read the display file. But why that is needed in your situation I can't tell - it is not normal practice.

                    There are better ways of doing it by using Data Structure I/O and keeping the display file fields and file fields separate (for one example).
                    [/QUOTE]

                    Comment


                    • #11
                      Originally posted by JustPassing View Post
                      You see, it's completely memory-related. I didn't even understand that there was such a thing as an input-buffer until just recently. And to understand concepts like VALUE, CONST, or "parameter passing by reference", I had to understand basic concepts about memory. I also still don't quite understand issues relating to garbage characters that can appear in certain memory addresses, when you have a large character field, for example, but only pass a small string, or why sometimes using %addr(Var) = *null doesn't work because of garbage characters that appear in that address even though the parameter was not passed (I now only use %parms in subprocedures because %addr only works the first time I call a subprocedure. Afterwards, there are always garbage characters in the address of the parameter).
                      And you didn't need to know there is a buffer because you can't do anything with the knowledge. There are very few occasions where it matters - and you have not described one.

                      "Garbage" in fields can be due to any number of things but when you say "pass a small string" do you mean from the command line? If so then read this and it will explain it all. Note the section on "https://wiki.midrange.com/index.php/Parameter_passing Command-Line or SBMJOB CMD(CALL) Parameter Problems"

                      "%addr(Var) = *null"
                      Will test if the address contained in the pointer Var is not valid. If there are garbage characters at that address it is not because the test failed. It is because you passed the wrong address or did not set up the memory properly. Can't guess at what you might have done wrong without knowing what you were trying to do. Pointer manipulation and testing is a raely used feature of RPG.

                      %Addr should _never_ be used to determine if a parm was passed or not (it sounds like this was the problem above). It is only valid to use this as a test against a parm that was specified with *OMIT. Or if your routine is explicitly passing pointers as parameters. Your assumption about first time call is just plain wrong. It might have "worked" on subsequent calls too - but "worked" with the wrong data. If you want I can explain this further but the simple answer is DON'T DO IT. %Parms and %ParmNum are the only valid ways to test if parameters are present or not.

                      Comment


                      • #12
                        I agree with Johnboy. I don't understand how the system handles memory in detail but I manage to code perfectly well. All the issues you have so far described are an issue in understanding the languages being used rather than anything else.

                        Originally posted by JustPassing View Post
                        Another example, just this week. We kept having "MCH3601 - Pointer not set for location referenced" error problems when calling RPG/400 or CLP programs from CLLE. When we'd change from CLLE to CLP, no problems. It turns out it's a "frequent issue" and has to do with how CLLE and RPG pass parameters. There's an explanation here https://archive.midrange.com/midrang.../msg00890.html and it talks about the "stack" and pointers (a concept I understand), but I don't know much about the concepts of "stacks" or the "heaps" or buffers or any of that.
                        Incidentally, that is an ancient article talking about v3r1 and I do not know if it is relevant anymore! It's also referring to procedure calls.
                        A MCH3601 error basically means that the called program is expecting a certain number of parameters and you aren't supplying them all. You need to check the parameters your RPG program is expecting and how many are being supplied. If they look fine, do you have multiple versions of the program on your system? The error is saying, that the called program is trying to read a pointer that was never passed. When you are calling your program, the parameters are passed "by reference" which means a pointer to the memory location where the parameter resides is passed. As a pointer was not supplied for at least one parameter, when the program tries to access it, this error is produced.

                        Understanding memory simply will not help you with this problem as it is a code issue. I would suggest if you have issues like this, you ask the question on these forums, posting the relevant code snippets. There are a lot of people here that can assist with your code and explain what is going on.

                        Comment


                        • #13
                          Thanks for all your feedback and advice, I really do appreciate it. Your posts have certainly made certain issues much clearer. However, I feel you're just not understanding the issues I'm having and this conversation seem to be going in circles.

                          If there are garbage characters at that address it is not because the test failed. It is because you passed the wrong address or did not set up the memory properly.
                          This is the whole point of this topic. I DON'T understand memory, so how do you expect me to set it up properly? How can I know if I've set the memory properly if I don't understand memory in the first place? You don't know what I've done. I don't know what I've done. So is not the solution for me to understand memory better, to know what I should/should not do and be able to, as you say, "set the memory properly"?

                          %Addr should _never_ be used to determine if a parm was passed or not (it sounds like this was the problem above).... Your assumption about first time call is just plain wrong.
                          And these are things I cannot guess and cannot understand without a better understanding of memory and its implementation. My intuitive understanding of memory does not forbid me from using %addr to test for parameter passing. If I am wrong, then is not the solution to understand why and not just have someone say to me that my understanding is wrong and to simply never use that in that way? Thank you for explaining why, but this is only one example out of a whole bunch more, and I don't think running every line of code here for feedback is realistic.

                          When the display file is read, the fields are copied to what you call the storage area. If you were then to read a disk file with the same field names, that content would be overwritten. So if you want the display file changes then yes - you would have to use RTNDTA and re-read the display file. But why that is needed in your situation I can't tell - it is not normal practice.
                          So, I forgot to mention a step in how we use it. Let's see if this is clearer:
                          1) Read the file
                          2) Exfmt the DSPF format
                          3) User makes modifications, presses enter
                          4) Program checks validity of modifications
                          5) If everything ok, chain the file again
                          6) Read the DSPF format
                          7) Update
                          We do not read the DSPF between pressing enter and checking validity. I could never understand RTNDTA because the values from the "previous input operation" are those from the EXFMT, which are not the modified values. By understanding that RTNDTA actually reads the "screen buffer" (apparently not "input buffer" like I had previously called it), I finally understood how it is able to "recover" the modified values. But for that, I had to understand that there is a thing called "screen buffer", that it's part of the memory separate from the "storage area" and that stores these modified values.

                          But then, understanding that raises new questions. Intuitively, I think I have the answers to them, but I have no certainty. When the user presses enter and we do our checks, which values in what memory are being checked? Say the format is F1 and one of the fields FIELD1, when we do something like "If FIELD1 = *blanks;", is it the field in the screen buffer that is being checked against *blanks? Intuitively, I would say yes. But the only way to be sure is if I could come across some documentation that explains this process in detail.

                          Why do I need to know this? Why can't I just content myself with knowing that I just have to put the RTNDTA keyword and read F1 right before the update? Because in knowing, I am sure I will be accessing the correct values in the correct memory at the right time. It gives me confidence. It makes me knowledgeable. Is that really not necessary to know?

                          If I call it "storage area", it's because that's what I think that's what we call the memory area where the values of variables are being stored. If this is not the case, don't hesitate to correct me, but it's also the illustration of why I say I need to understand the different types of memories and know the right names for them instead of calling them my own names. To know that this is called the "buffer" and that the "stack" and not just be, "There where it is, wherever it is, in the memory, somewhere in there". It doesn't make me a comptent developer to use such imprecise terms.


                          Again, I appreciate all your answers. We were told when I was learning to program for IBM i that the AS400 was developed primarily for accountants, not developers or computer scientists and that many of the past IBM i "developers" only had a basic understanding of all this stuff, just enough to create programs necessary for their work.

                          I am not an accountant. While I don't aspire to work at IBM or to know exactly how the IBM i OS was coded or exactly how everything was implemented, there are some things that not understanding just seems incompatible with being a competent developer. Memory is one of them. Not only that, but I'm still young and I don't think I will spend the rest of my life as an IBM i developer. Whatever knowledge I could gain from better understanding these subjects would without a doubt only be beneficial to me. In no way would I be wasting my time. Or perhaps in a few decades, if I'm still in this domain and IBM i still exists, I may want to think about training new developers. And for that, saying "oh somewhere in there" when talking about memory is not going to cut it.

                          So I thank you for your input and I'll give a simple answer to the main question you ask : Why do I want to know these things? To understand.

                          Anyway, I think I know where to go from here and I thank you once again for your input. You can answer whatever parts of my post you want, but I've spent way too much time in this topic, so I may not reply. It's better I start cracking books and getting to reading documentation.

                          If I have other questions relating to specific points, I'll be sure to open new topics and I'll appreciate whatever input you or anyone else can give me there. But I think this discussion ends here for me.

                          Thanks.

                          Comment


                          • #14
                            Originally posted by JustPassing View Post

                            <snip>
                            This is the whole point of this topic. I DON'T understand memory, so how do you expect me to set it up properly? How can I know if I've set the memory properly if I don't understand memory in the first place? You don't know what I've done. I don't know what I've done. So is not the solution for me to understand memory better, to know what I should/should not do and be able to, as you say, "set the memory properly"?

                            And these are things I cannot guess and cannot understand without a better understanding of memory and its implementation. My intuitive understanding of memory does not forbid me from using %addr to test for parameter passing. If I am wrong, then is not the solution to understand why and not just have someone say to me that my understanding is wrong and to simply never use that in that way? Thank you for explaining why, but this is only one example out of a whole bunch more, and I don't think running every line of code here for feedback is realistic.
                            I do hope you read this because there is some reading material referenced.

                            The topic you need to study is parameter passing - wth emphasis on RPG. Read these articles. https://www.itjungle.com/2016/11/29/fhg112916-story01/ and https://www.itjungle.com/2017/02/20/...us-procedures/ I think you will find most of the issues you have encountered are covered there. Apologies for not having referenced them earlier.

                            Any computer language has rules. And any computer language can be abused. A study of how to handle optional parameters in RPG should have shown you examples using %Parms (or exceptionally A CEExxxx API call. It is highly unlikely that you'd have seen an example of using %Addr - that might be valid as a technique in C (on some platforms) but it won't work reliably in RPG. The reason is simple. There may be a valid pointer left on the stack from a previous call. Suppose that you called a procedure passing it 2 parameters A and B. Pointers to A and B are now on the stack in the first two positions. If the procedure is called a second time with a single parameter C the stack will now contain C and B (because the unused stack entires are not overwritten). %Parms knows that only 1 parameter was passed, but if you attempt to check %Addr of the second parameter the system looks at the second position of the stack and checks that pointer. It points to B!

                            I could go on but you hopefully get the picture.

                            Originally posted by JustPassing View Post


                            So, I forgot to mention a step in how we use it. Let's see if this is clearer:
                            1) Read the file
                            2) Exfmt the DSPF format
                            3) User makes modifications, presses enter
                            4) Program checks validity of modifications
                            5) If everything ok, chain the file again
                            6) Read the DSPF format
                            7) Update
                            We do not read the DSPF between pressing enter and checking validity. I could never understand RTNDTA because the values from the "previous input operation" are those from the EXFMT, which are not the modified values. By understanding that RTNDTA actually reads the "screen buffer" (apparently not "input buffer" like I had previously called it), I finally understood how it is able to "recover" the modified values. But for that, I had to understand that there is a thing called "screen buffer", that it's part of the memory separate from the "storage area" and that stores these modified values.

                            But then, understanding that raises new questions. Intuitively, I think I have the answers to them, but I have no certainty. When the user presses enter and we do our checks, which values in what memory are being checked? Say the format is F1 and one of the fields FIELD1, when we do something like "If FIELD1 = *blanks;", is it the field in the screen buffer that is being checked against *blanks? Intuitively, I would say yes. But the only way to be sure is if I could come across some documentation that explains this process in detail.
                            If the validation is in the RPG logic then it is the regular storage area that you are checking. As I said earlier - that is the ONLY memory you can access.

                            As I said earlier the technique being used here is somewhat unusual. You are not the only person who has trouble understanding it - most RPG programmers would have difficulty because it is unusual.

                            When you re-read the screen (exploiting the RTNDTA) you are basically asking the _terminal_ to send the data again. In practice it probably comes from workstation data management not the device itself, but the important thing is that RPG knows nothing about it.

                            Originally posted by JustPassing View Post
                            Why do I need to know this? Why can't I just content myself with knowing that I just have to put the RTNDTA keyword and read F1 right before the update? Because in knowing, I am sure I will be accessing the correct values in the correct memory at the right time. It gives me confidence. It makes me knowledgeable. Is that really not necessary to know?

                            If I call it "storage area", it's because that's what I think that's what we call the memory area where the values of variables are being stored. If this is not the case, don't hesitate to correct me, but it's also the illustration of why I say I need to understand the different types of memories and know the right names for them instead of calling them my own names. To know that this is called the "buffer" and that the "stack" and not just be, "There where it is, wherever it is, in the memory, somewhere in there". It doesn't make me a comptent developer to use such imprecise terms.


                            Again, I appreciate all your answers. We were told when I was learning to program for IBM i that the AS400 was developed primarily for accountants, not developers or computer scientists and that many of the past IBM i "developers" only had a basic understanding of all this stuff, just enough to create programs necessary for their work.

                            I am not an accountant. While I don't aspire to work at IBM or to know exactly how the IBM i OS was coded or exactly how everything was implemented, there are some things that not understanding just seems incompatible with being a competent developer. Memory is one of them. Not only that, but I'm still young and I don't think I will spend the rest of my life as an IBM i developer. Whatever knowledge I could gain from better understanding these subjects would without a doubt only be beneficial to me. In no way would I be wasting my time. Or perhaps in a few decades, if I'm still in this domain and IBM i still exists, I may want to think about training new developers. And for that, saying "oh somewhere in there" when talking about memory is not going to cut it.
                            Just about everything you have been told about the system and "accountants" is untrue. It was sorta-kinda true some 40+ years ago with some of the predecessors of the IBM i - but the IBM i (and its predecessors the AS/400 and System/38 were never designed for accountants - they were designed to be business systems- as opposed to scientific systems. The "accountants" bit probably comes from the early days of midrange computer systems when accountants were often trained as programmers and went on to computerized their book keeping systems. This was true of all midrange systems. Only mainframes and scientific systems had "professional" university trained programmers. In fact when I started there were no Comp Sci degrees. Just math with computer options. That is the era in which the "accountants" idea originates.

                            IBM i runs on IBM's Power systems - the same hardware behind the current Watson system and the same hardware that won Jeopardy! https://www.techrepublic.com/article...ts-to-do-next/ The same hardware runs AIX and Linux.

                            Originally posted by JustPassing View Post
                            So I thank you for your input and I'll give a simple answer to the main question you ask : Why do I want to know these things? To understand.

                            Anyway, I think I know where to go from here and I thank you once again for your input. You can answer whatever parts of my post you want, but I've spent way too much time in this topic, so I may not reply. It's better I start cracking books and getting to reading documentation.

                            If I have other questions relating to specific points, I'll be sure to open new topics and I'll appreciate whatever input you or anyone else can give me there. But I think this discussion ends here for me.

                            Thanks.
                            You still haven't answered my question about what hardware and languages you do know. It would be so much easier to help you understand if I knew your background.

                            I would also suggest that you ask questions here and elsewhere if you are uncertain. Guessing and trying to work things out is admirable and I do it all the time. But if you are not careful it can take you down rabbit holes and confuse things further. Had you asked here about parameter passing problems wee could have sorted you out really quickly.

                            I admire your stick-to-it-ness and your desire to learn - just be careful fo making too many assumptions - particularly when it comes to languages like RPG.

                            Comment


                            • #15
                              Perhaps if you told us about systems which you have programming experience with we could better help you.

                              Comment

                              Working...
                              X