1 / 69

TL: More types

TL: More types. Programming Fundamentals 23 Feliks Klu ź niak. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: const size_of_NetID = 9 ; type NetID = string[ size_of_NetID ] ;

enoch
Download Presentation

TL: More types

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. TL: More types Programming Fundamentals 23 Feliks Kluźniak TL: More types

  2. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; TL: More types

  3. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; TL: More types

  4. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; If we have a procedure that copies one string to another, we can write: copy_string( “abc099000”, our_class[ 0 ] ); TL: More types

  5. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; If we have a procedure that copies one string to another, we can write: copy_string( “abc099000”, our_class[ 0 ] ); We might also want to write out an element: while k != size( our_class[ j ] ) do write( stdout, our_class[ j ][ k ] ); k := k + 1 od TL: More types

  6. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; If we have a procedure that copies one string to another, we can write: copy_string( “abc099000”, our_class[ 0 ] ); We might also want to write out an element: while k != size( our_class[ j ] )do write( stdout, our_class[ j ][ k ] ); k := k + 1 od What is the value of this expression? TL: More types

  7. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; If we have a procedure that copies one string to another, we can write: copy_string( “abc099000”, our_class[ 0 ] ); We might also want to write out an element: while k != size( our_class[ j ] ) do write( stdout, our_class[ j ][ k ] ); k := k + 1 od The type of our_class[ j ] is WHAT? TL: More types

  8. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; If we have a procedure that copies one string to another, we can write: copy_string( “abc099000”, our_class[ 0 ] ); We might also want to write out an element: while k != size( our_class[ j ] ) do write( stdout, our_class[ j ][ k ] ); k := k + 1 od The type of our_class[ j ] is NetID, so the type of our_class[ j ][ k ] is WHAT? TL: More types

  9. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; If we have a procedure that copies one string to another, we can write: copy_string( “abc099000”, our_class[ 0 ] ); We might also want to write out an element: while k != size( our_class[ j ] ) do write( stdout, our_class[ j ][ k ] ); k := k + 1 od The type of our_class[ j ] is NetID, so the type of our_class[ j ][ k ] is char . TL: More types

  10. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; We can continue to build the hierarchy of data types, for example: type Classes = Class[] ; type Course = Classes[ 6 ] ; var cs1336 : Course; … write( stdout, cs1336[ i ][ j ][ k ] ) TL: More types

  11. Upto now we have only seen arrays of integers and characters. But an array can have elements of any concrete type. For example: constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; We might want to associate each NetID in a class with the student’s age. This can be done by keeping the age in a separate array: type Ages = IntArray[ size_of_Class ] ; varour_ages : Ages ; … write_string( stdout, our_class[ k ] ); write( stdout, ‘ ‘ ); write_int( stdout, our_ages[ k ] ); write( stdout, ‘\n’ ) TL: More types

  12. constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; type Ages = IntArray[ size_of_Class ] ; varour_ages : Ages ; Another way to do this is to declare an array of records. TL: More types

  13. constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; type Ages = IntArray[ size_of_Class ] ; varour_ages : Ages ; Another way to do this is to declare an array of records. Unlike an array, which is a collection of elements of the same type, a record is a collection of fields of various types. For example: type Student = record id : NetID ; age : int end TL: More types

  14. constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; type Ages = IntArray[ size_of_Class ] ; varour_ages : Ages ; Another way to do this is to declare an array of records. Unlike an array, which is a collection of elements of the same type, a record is a collection of fields of various types. For example: type Student = record id : NetID ; age : int end NOTE: The type of a field must be concrete. TL: More types

  15. constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; type Ages = IntArray[ size_of_Class ] ; varour_ages : Ages ; Another way to do this is to declare an array of records. Unlike an array, which is a collection of elements of the same type, a record is a collection of fields of various types. For example: type Student = record id : NetID ; age : int end ; varst : Student TL: More types

  16. constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; type Ages = IntArray[ size_of_Class ] ; varour_ages : Ages ; Another way to do this is to declare an array of records. Unlike an array, which is a collection of elements of the same type, a record is a collection of fields of various types. For example: type Student = record id : NetID ; age : int end ; varst : Student st: st.id[0]: st.id[1]: st.id[2]: st.id[3]: st.id[4]: st.id[5]: st.id[6]: st.id[7]: st.id[8]: st.age: TL: More types

  17. constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; type Ages = IntArray[ size_of_Class ] ; varour_ages : Ages ; Another way to do this is to declare an array of records. Unlike an array, which is a collection of elements of the same type, a record is a collection of fields of various types. For example: type Student = record id : NetID ; age : int end ; varst : Student The fields of a record variable are accessed by using “dot notation”: copy_string( “abc099000”, st.id ) ; st.age := 19 st: st.id[0]: st.id[1]: st.id[2]: st.id[3]: st.id[4]: st.id[5]: st.id[6]: st.id[7]: st.id[8]: st.age: TL: More types

  18. constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; type Ages = IntArray[ size_of_Class ] ; varour_ages : Ages ; type Student = record id : NetID ; age : int end ; varst : Student We can, of course, have an array of records. Here is a redefinition of our example: type ArrayOfStudent = Student [] ; type Class = ArrayOfStudent[ size_of_Class ] ; varour_class : Class; TL: More types

  19. constsize_of_NetID = 9 ; typeNetID = string[ size_of_NetID ] ; typeArrayOfNetID = NetID [] ; constsize_of_Class = 60 ; type Class = ArrayOfNetID[ size_of_Class ] ; varour_class : Class; type Ages = IntArray[ size_of_Class ] ; varour_ages : Ages ; type Student = record id : NetID ; age : int end ; type ArrayOfStudent = Student [] ; type Class = ArrayOfStudent[ size_of_Class ] ; varour_class : Class; This is more convenient than the green example above. We keep everything in one place, need not remember that there are two related arrays, can write procedures that operate on records of type Student, and pass single elements as arguments: e.g., birthday( our_class[ k ] ) . TL: More types

  20. The type of a record field can be any concrete type. We already saw that it can be an array. It can also be a record. For example: constmax_size_of_name = 100; typeNameStore = string[ max_size_of_name ]; type Name = record nm : NameStore; ln : int% length of name in nm end; type Student = record id : NetID; name : Name; age : int end TL: More types

  21. typeNameStore = string[ max_size_of_name ]; type Name = record nm : NameStore; ln : int% length of name in nm end; type Student = record id : NetID; name : Name; age : int end Now we can write out a student’s data as follows: procwr_student ( ref out : output, refconstst : Student ) begin var j : int; write_string( out, st.id ); write( out, ‘ ‘ ); write_int( out, age ); write( out, ‘\n’ ); j := 0; while j != st.name.lndo % write just the name, not the extra characters in nm write( out, st.name.nm[ j ] ); j := j + 1 od end TL: More types

  22. We have great flexibility in designing our data structures. If the data structures for our application are designed carefully and with thought, most of the code more or less “writes itself”. TL: More types

  23. We have great flexibility in designing our data structures. If the data structures for our application are designed carefully and with thought, most of the code more or less “writes itself”. If the data structures are not designed well, the code can become quite hairy. TL: More types

  24. We have great flexibility in designing our data structures. If the data structures for our application are designed carefully and with thought, most of the code more or less “writes itself”. If the data structures are not designed well, the code can become quite hairy. If things get too complicated, it might be a good idea to throw everything into the waste paper basket and redesign from scratch. TL: More types

  25. We have great flexibility in designing our data structures. If the data structures for our application are designed carefully and with thought, most of the code more or less “writes itself”. If the data structures are not designed well, the code can become quite hairy. If things get too complicated, it might be a good idea to throw everything into the waste paper basket and redesign from scratch. Even the most experienced programmers have to do that sometimes! TL: More types

  26. typeNameStore = string[ max_size_of_name ] ; type Name = record nm : NameStore; ln : int% length of name in nm end; type Student = record id : NetID; name : Name; age : int end This structure is not very satisfactory! We allocate the same amount of memory for the name of each student. TL: More types

  27. typeNameStore = string[ max_size_of_name ] ; type Name = record nm : NameStore; ln : int% length of name in nm end; type Student = record id : NetID; name : Name; age : int end This structure is not very satisfactory! We allocate the same amount of memory for the name of each student. If max_size_of_name is small, it will often be too small. If it is large, it will often be too large, and memory will be wasted. Even a length of 100 will be too small in some cases, though too large in most. TL: More types

  28. typeNameStore = string[ max_size_of_name ] ; type Name = record nm : NameStore; ln : int% length of name in nm end; type Student = record id : NetID; name : Name; age : int end This structure is not very satisfactory! We allocate the same amount of memory for the name of each student. If max_size_of_name is small, it will often be too small. If it is large, it will often be too large, and memory will be wasted. Even a length of 100 will be too small in some cases, though too large in most. One way to solve this problem is to allocate strings of the right size from a common pool of memory as the need arises, TL: More types

  29. typeNameStore = string[ max_size_of_name ] ; type Name = record nm : NameStore; ln : int% length of name in nm end; type Student = record id : NetID; name : Name; age : int end This structure is not very satisfactory! We allocate the same amount of memory for the name of each student. If max_size_of_name is small, it will often be too small. If it is large, it will often be too large, and memory will be wasted. Even a length of 100 will be too small in some cases, though too large in most. One way to solve this problem is to allocate strings of the right size from a common pool of memory as the need arises, and to make the records hold addresses of such strings. Such addresses are known as pointers. TL: More types

  30. typeNameStore = string[ max_size_of_name ] ; type Name = record nm : NameStore; ln : int% length of name in nm end; type Student = record id : NetID; name : Name; age : int end s.name: s.name.nm: 100 s.name: 3 ‘J’ ‘J’ ‘o’ ‘o’ ‘e’ ‘e’ unused s.name.ln: 3 TL: More types

  31. typeNameStore = string[ max_size_of_name ] ; type Name = record nm : NameStore; ln : int% length of name in nm end; type Student = record id : NetID; name : Name; age : int end s.name: s.name.nm: 100 s.name: 3 ‘J’ ‘J’ ‘o’ ‘o’ ‘e’ ‘e’ unused Where and how do we get this memory? s.name.ln: 3 TL: More types

  32. Most modern programming languages have very similar runtime models. The memory occupied by a TL program is organized like this: The program, translated to machine code Code The recursion stack (we will talk about this in a minute) The stack Free storage: room for the stack or the heap to grow Free space Storage for long-lived objects (we will talk about this in a few weeks) The heap TL: More types

  33. So we can allocate memory from the heap as the program is running, and access the allocated fragments by using their addresses. TL: More types

  34. So we can allocate memory from the heap as the program is running, and access the allocated fragments by using their addresses. Such addresses are called pointers . TL: More types

  35. So we can allocate memory from the heap as the program is running, and access the allocated fragments by using their addresses. Such addresses are called pointers . TL being a strongly-typed high-level language, we must of course make sure that the use of pointers does not compromise type safety, i.e., that there is no danger, e.g., of mistaking a string for an integer array. TL: More types

  36. So we can allocate memory from the heap as the program is running, and access the allocated fragments by using their addresses. Such addresses are called pointers . TL being a strongly-typed high-level language, we must of course make sure that the use of pointers does not compromise type safety, i.e., that there is no danger, e.g., of mistaking a string for an integer array. Like in many other languages (since the introduction of Pascal), we do this by restricting each pointer to be an address of a variable (“object”) of a particular type. TL: More types

  37. So we can allocate memory from the heap as the program is running, and access the allocated fragments by using their addresses. Such addresses are called pointers . TL being a strongly-typed high-level language, we must of course make sure that the use of pointers does not compromise type safety, i.e., that there is no danger, e.g., of mistaking a string for an integer array. Like in many other languages (since the introduction of Pascal), we do this by restricting each pointer to be an address of a variable (“object”) of a particular type. In other words, each pointer has some type, which is associated with the type of the objects that can be referenced by the pointer. TL: More types

  38. So we can allocate memory from the heap as the program is running, and access the allocated fragments by using their addresses. Such addresses are called pointers . TL being a strongly-typed high-level language, we must of course make sure that the use of pointers does not compromise type safety, i.e., that there is no danger, e.g., of mistaking a string for an integer array. Like in many other languages (since the introduction of Pascal), we do this by restricting each pointer to be an address of a variable (“object”) of a particular type. In other words, each pointer has some type, which is associated with the type of the objects that can be referenced by the pointer. The type of a pointer is declared as follows: type TP = T ^ ; TL: More types

  39. So we can allocate memory from the heap as the program is running, and access the allocated fragments by using their addresses. Such addresses are called pointers . TL being a strongly-typed high-level language, we must of course make sure that the use of pointers does not compromise type safety, i.e., that there is no danger, e.g., of mistaking a string for an integer array. Like in many other languages (since the introduction of Pascal), we do this by restricting each pointer to be an address of a variable (“object”) of a particular type. In other words, each pointer has some type, which is associated with the type of the objects that can be referenced by the pointer. The type of a pointer is declared as follows: type TP = T ^ ; Here, TP is the name of the declared pointer type, and T is the name of some other type, which we call the referenced type of TP : values of type TP are references to (i.e., addresses of) values of the referenced type. TL: More types

  40. So we can allocate memory from the heap as the program is running, and access the allocated fragments by using their addresses. Such addresses are called pointers . TL being a strongly-typed high-level language, we must of course make sure that the use of pointers does not compromise type safety, i.e., that there is no danger, e.g., of mistaking a string for an integer array. Like in many other languages (since the introduction of Pascal), we do this by restricting each pointer to be an address of a variable (“object”) of a particular type. In other words, each pointer has some type, which is associated with the type of the objects that can be referenced by the pointer. The type of a pointer is declared as follows: type TP = T ^ ; Here, TP is the name of the declared pointer type, and T is the name of some other type, which we call the referenced type of TP : values of type TP are references to (i.e., addresses of) values of the referenced type. The character ^ is similar to an arrow, which is often used to illustrate references. TL: More types

  41. For example, typeStringP = string ^ declares the type of pointers to all strings (notice that string is a generic array type). TL: More types

  42. For example, typeStringP = string ^ declares the type of pointers to all strings (notice that string is a generic array type). We can now modify our example: type Student = record name : StringP ; id : NetId; age : int end name: 3 id: ‘J’ ‘o’ age: ‘e’ 22 TL: More types

  43. To access the name, we must dereference the pointer contained in the field name by applying the postfix operator ^ : n := size( s . name ^ ) ; s . name ^ [ 0 ] = ‘J’ TL: More types

  44. To access the name, we must dereference the pointer contained in the field name by applying the postfix operator ^ : n := size( s . name ^ ) ; s . name ^ [ 0 ] = ‘J’ If we want to allocate storage for a name (or for any other array) we must use a built-in procedure called newa() , with two arguments. TL: More types

  45. To access the name, we must dereference the pointer contained in the field name by applying the postfix operator ^ : n := size( s . name ^ ) ; s . name ^ [ 0 ] = ‘J’ If we want to allocate storage for a name (or for any other array) we must use a built-in procedure called newa() , with two arguments. For example, newa( s . name , 3 ) will create a name that is 3 characters long, and assign its address to s.name . NOTE: Only the size field of the name will be initialized! TL: More types

  46. When a pointer does not refer to any value, it should have the value nil which stands for “no address”. TL: More types

  47. When a pointer does not refer to any value, it should have the value nil which stands for “no address”. nil is a valid value for every pointer type. TL: More types

  48. When a pointer does not refer to any value, it should have the value nil which stands for “no address”. nil is a valid value for every pointer type. A pointer with this value is called a nullpointer. TL: More types

  49. When a pointer does not refer to any value, it should have the value nil which stands for “no address”. nil is a valid value for every pointer type. A pointer with this value is called a nullpointer. In TL an attempt to dereference a null pointer will cause immediate termination of the program, with helpful diagnostics. TL: More types

  50. When a pointer does not refer to any value, it should have the value nil which stands for “no address”. nil is a valid value for every pointer type. A pointer with this value is called a nullpointer. In TL an attempt to dereference a null pointer will cause immediate termination of the program, with helpful diagnostics. In other languages things might be different, e.g., in C you are likely to get a core dump. TL: More types

More Related