Package compilation fails with ORA-00927: missing equal sign - oracle

I am creating a package and I don't understand why the error occurs.
My package:
create or replace PACKAGE test_action AS
subj CHAR default '';
count_student INTEGER default 0;
FUNCTION count_positive(subject CHAR) RETURN INTEGER;
PROCEDURE number_requests;
END test_action;
Package body:
CREATE OR REPLACE PACKAGE BODY test_action AS
FUNCTION count_positive(sub CHAR) RETURN INTEGER
AS
BEGIN
count_student := 0;
subj := sub;
SELECT COUNT(*) INTO count_student
FROM D8_EXAMS E JOIN D8_SUBJECT S
ON E.subj_id = S.subj_id
WHERE E.mark > 3 AND S.subj_name = subject
GROUP BY S.subj_name;
number_requests;
return count_student;
END count_positive;
PROCEDURE number_requests AS
BEGIN
INSERT INTO package_table (subject,counts,callCount)
VALUES (subj,count_student,1);
exception
when dup_val_on_index then
update t
set callCount := callCount + 1,
set counts := count_student
where subject = subj;
END number_requests;
END test_action;
and then I get an error
if I try to add assignment to variables before the function description, then a new error occurs

Because - as error says - you're missing equal sign (it is just =, not :=), and there's only one set keyword per update:
update t
set callCount = callCount + 1,
counts = count_student
where subject = subj;
Apart from that:
function declaration in package body must match the one in package specification
in exception, you're updating table t; shouldn't that be package_table?
select count(*) has group by clause; to me, it smells like possible point to raise too_many_rows error you didn't handle
This, at least, compiles: package spec:
SQL> CREATE OR REPLACE PACKAGE test_action
2 AS
3 subj CHAR DEFAULT '';
4 count_student INTEGER DEFAULT 0;
5
6 FUNCTION count_positive (sub CHAR)
7 RETURN INTEGER;
8
9 PROCEDURE number_requests;
10 END test_action;
11 /
Package created.
Package body:
SQL> CREATE OR REPLACE PACKAGE BODY test_action
2 AS
3 FUNCTION count_positive (sub CHAR)
4 RETURN INTEGER
5 AS
6 BEGIN
7 count_student := 0;
8 subj := sub;
9
10 SELECT COUNT (*)
11 INTO count_student
12 FROM D8_EXAMS E JOIN D8_SUBJECT S ON E.subj_id = S.subj_id
13 WHERE E.mark > 3
14 AND S.subj_name = sub
15 GROUP BY S.subj_name;
16
17 number_requests;
18 RETURN count_student;
19 END count_positive;
20
21 PROCEDURE number_requests
22 AS
23 BEGIN
24 INSERT INTO package_table (subject, counts, callCount)
25 VALUES (subj, count_student, 1);
26 EXCEPTION
27 WHEN DUP_VAL_ON_INDEX
28 THEN
29 UPDATE package_table
30 SET callCount = callCount + 1, counts = count_student
31 WHERE subject = subj;
32 END number_requests;
33 END test_action;
34 /
Package body created.
SQL>

Related

How can I fix these errors in plsql code?

CREATE TABLE user_man_sys(
user_id INT NOT NULL,
user_name NVARCHAR2(20) NOT NULL,
user_password INT ,
created_date DATE ,
PRIMARY KEY(user_id)
);
CREATE OR REPLACE PACKAGE mypackage AS
PROCEDURE add_user(
u_id user_man_sys.user_id%type,
u_name user_man_sys.user_name%type,
u_password user_man_sys.user_password%type,
u_created_data user_man_sys.created_date%type);
PROCEDURE Checkuserlogin(new_username user_man_sys.user_name%type,
new_password user_man_sys.user_password%type )
PROCEDURE rest_password ( r_password user_man_sys.user_password%type)
END mypackage ;
/
CREATE OR REPLACE PACKAGE BODY mypackage AS
PROCEDURE add_user(
u_id user_man_sys.user_id%type,
u_name user_man_sys.user_name%type,
u_password user_man_sys.user_password%type,
u_created_data user_man_sys.created_date%type)
IS
BEGIN
INSERT INTO user_man_sys(user_id,user_name ,user_password ,created_date)
VALUES(u_id, u_name,u_password,u_created_data );
END add_user;
PROCEDURE Checkuserlogin(new_usernameuser_man_sys.user_name%type,
new_password user_man_sys.user_password%type)
IS
BEGIN
SET NOCOUNT ON
SELECT CASE WHEN EXISTS(SELECT NULL FROM user_man_sysWHERE user_id=new_username AND user_password=new_password)
THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT)
END Checkuserlogin;
PROCEDURE rest_password ( r_password user_man_sys.user_password%type,r_user user_man_sys.user_name%type)
IS
BEGIN
UPDATE credentials
SET password = r_password -- use as parameter in procedure
WHERE username = r_user;
-- or you can include "and id = p_id" in where clause
IF SQL%ROWCOUNT > 0
THEN
COMMIT;
RETURN 'Password Reset Successful.';
ELSE
RETURN 'Password Reset Failed. Invalid User Name';
END IF;
END rest_password ;
end mypackage;
/
My code performes these tasks :
1)procedure to create user.
2)procedure to reset password.
3)procedure to check login cardinals.
I want to repair this error in this code if i ceate a package or the body of the package shows a mistacke (the package or the body of the the package are configured with translation errors)
How can i fix it?
Quite a few errors.
Table is created with no problems:
SQL> CREATE TABLE user_man_sys
2 (
3 user_id INT NOT NULL,
4 user_name NVARCHAR2 (20) NOT NULL,
5 user_password INT,
6 created_date DATE,
7 PRIMARY KEY (user_id)
8 );
Table created.
This is a table that's getting updated; I don't have it, so I'm creating a dummy one, just to make package body compile:
SQL> CREATE TABLE credentials
2 (
3 password VARCHAR2 (10),
4 username VARCHAR2 (20)
5 );
Table created.
Package specification: you're missing semi-colons (as terminators); description of procedures in body must match the ones in specification (rest_password is wrong, then; also, as it can't return anything (it is not a function, I added an out parameter):
SQL> CREATE OR REPLACE PACKAGE mypackage
2 AS
3 PROCEDURE add_user (u_id user_man_sys.user_id%TYPE,
4 u_name user_man_sys.user_name%TYPE,
5 u_password user_man_sys.user_password%TYPE,
6 u_created_data user_man_sys.created_date%TYPE);
7
8 PROCEDURE Checkuserlogin (new_username user_man_sys.user_name%TYPE,
9 new_password user_man_sys.user_password%TYPE);
10
11 PROCEDURE rest_password (r_password user_man_sys.user_password%TYPE,
12 r_user user_man_sys.user_name%TYPE,
13 par_result OUT VARCHAR2);
14 END mypackage;
15 /
Package created.
Package body: typos (missing spaces); set belongs to SQL*Plus, not PL/SQL procedures; Checkuserlogin's select statement requires an into clause and valid datatype (bit isn't):
SQL> CREATE OR REPLACE PACKAGE BODY mypackage
2 AS
3 PROCEDURE add_user (u_id user_man_sys.user_id%TYPE,
4 u_name user_man_sys.user_name%TYPE,
5 u_password user_man_sys.user_password%TYPE,
6 u_created_data user_man_sys.created_date%TYPE)
7 IS
8 BEGIN
9 INSERT INTO user_man_sys (user_id,
10 user_name,
11 user_password,
12 created_date)
13 VALUES (u_id,
14 u_name,
15 u_password,
16 u_created_data);
17 END add_user;
18
19 PROCEDURE Checkuserlogin (new_username user_man_sys.user_name%TYPE,
20 new_password user_man_sys.user_password%TYPE)
21 IS
22 l_val NUMBER;
23 BEGIN
24 --SET NOCOUNT ON
25
26 SELECT CASE
27 WHEN EXISTS
28 (SELECT NULL
29 FROM user_man_sys
30 WHERE user_id = new_username
31 AND user_password = new_password)
32 THEN
33 1
34 ELSE
35 0
36 END
37 INTO l_val
38 FROM DUAL;
39 END Checkuserlogin;
40
41 PROCEDURE rest_password (r_password user_man_sys.user_password%TYPE,
42 r_user user_man_sys.user_name%TYPE,
43 par_result OUT VARCHAR2)
44 IS
45 BEGIN
46 UPDATE credentials
47 SET password = r_password -- use as parameter in procedure
48 WHERE username = r_user;
49
50 -- or you can include "and id = p_id" in where clause
51 IF SQL%ROWCOUNT > 0
52 THEN
53 COMMIT;
54 par_result := 'Password Reset Successful.';
55 ELSE
56 par_result := 'Password Reset Failed. Invalid User Name';
57 END IF;
58 END rest_password;
59 END mypackage;
60 /
Package body created.
SQL>
That's it, as far as compilation problems is concerned. Does your code do what you planned, I wouldn't know. Test it yourself.

PLS-00103: Encountered the symbol " " when expecting one of the following: := . ( # % ; not null range default character

Why doesn't this work?
Any advice or solutions are greatly appreciated.
CREATE OR REPLACE TRIGGER OverReading
BEFORE UPDATE OR INSERT ON MeterReadings
FOR EACH ROW
DECLARE
emp_counter INTEGER;
max_meter INTEGER : = 5;
BEGIN
SELECT COUNT(EmployeeId) INTO emp_counter
FROM MeterReadings
WHERE EmployeeId = :NEW.EmployeeId;
IF : OLD.EmployeeId = NEW.EmployeeId THEN
RETURN;
ELSIF emp_counter >= max_meter THEN
raise_application_error(-20900,'Employee are limited to a maximum of 5 meters');
END IF;
END;
/
The Error that is thrown to me
Three syntax errors, all of them related to : character.
When fixed, trigger compiles:
SQL> CREATE OR REPLACE TRIGGER OverReading
2 BEFORE UPDATE OR INSERT ON MeterReadings
3 FOR EACH ROW
4 DECLARE
5 emp_counter INTEGER;
6 max_meter INTEGER := 5; --> here
7 BEGIN
8 SELECT COUNT(EmployeeId) INTO emp_counter
9 FROM MeterReadings
10 WHERE EmployeeId = :NEW.EmployeeId;
11 IF :OLD.EmployeeId = :NEW.EmployeeId THEN --> 2x here
12 RETURN;
13 ELSIF emp_counter >= max_meter THEN
14 raise_application_error(-20900,'Employee are limited to a maximum of 5 meters');
15 END IF;
16 END;
17 /
Trigger created.
SQL>
However: this code will run if you insert rows one-by-one. Otherwise, it will raise mutating table error as you're selecting from the same table you're inserting into (which is not allowed). If that bothers you, there are ways to fix it. Depending on database version you use, it could be a compound trigger or a type + package option.

Insert Into A Table With 200 Columns

We Have A Table in our Oracle DB With 200 Columns Which we have to do Insert into it and we have an C program which inserts requests in that table and it uses Pro*C to Call an stored program in oracle DB to do the job.
Currently we serialize all fields with TLV format{Tag-Length-Value} and have a function with a Varchar2 parameter(the serialized list of fields). for example:
008603701212345678901201100611111104800622222220000633333320100644444401201420200321164712
more human readable:
0086 037 012 123456789012 011 006 111111 048 006 222222 200 006 333333 201 006 444444 012 014 20200321164712
which means:
String Len:86
Field037 with len 12:123456789012
Field011 with len 6:111111
Field048 with len 6:222222
Field200 with len 6:333333
Field201 with len 6:444444
Field012 with len 14:20200321164712
each of these fields map to a field in the table, the stored program parses the huge string and fills them into a rowtype and finally inserts the row in the table.
For years it was working well, but when we get ready for more requests(thus more inserts) our DBA says we are using a lot of CPU for de-serializing the TLV. So we have to change our insert method.
I Currently created an structure in C and map all fields in it and call:
typedef struct
{
char field37[12+1];
char field11[6+1];
char field48[6+1];
char field200[6+1];
char field201[6+1];
char field12[14+1];
} NewRecord;
NewRecord newRecord;
TlvToStruct(sTlv, &newRecord);//Mapper Function
EXEC SQL INSERT INTO MY_TABLE(FIELD37, FIELD11, FIELD200, FIELD201, FIELD12) VALUES(:newRecord);
EXEC SQL COMMIT WORK RELEASE;
This approach works well for now, but my question is: Should I continue developing and add all 200 fields to this structure and use this approach or it's better to use PLSQL call(maybe develop and using another insert function) instead of this SQL Insert?
I am currently aware of PLSQL benefits, but there is some problems with it here:
1- Pro*C does not support PLSQL Records
[Oracle Document]1
2- It is not so reasonable to have a function with 200 parameters!
3- We use Types in plsql but never used them in Pro*C(actually I tried once and I failed long ago)
I tried to describe the problem here, if it is unclear please ask
Thanks
==================================================
EDIT:
Here is our old Get_Tag and Put_Tag functions:
FUNCTION GET_TAG(P_TAG_NAME IN VARCHAR2, P_TLV_STRG IN VARCHAR2, P_TAG_LEN OUT NOCOPY PLS_INTEGER, P_TAG_VALUE OUT NOCOPY VARCHAR2)
RETURN PLS_INTEGER IS
V_COUNTER_LOOP PLS_INTEGER := 1;
V_TLV_STRG VARCHAR2(4096) := SUBSTR(P_TLV_STRG, 5);
BEGIN
P_TAG_VALUE := NULL;
P_TAG_LEN := 0;
WHILE V_COUNTER_LOOP < LENGTH(V_TLV_STRG) LOOP
IF SUBSTR(V_TLV_STRG, V_COUNTER_LOOP, 3) = P_TAG_NAME THEN
P_TAG_LEN := TO_NUMBER(SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 3, 3));
P_TAG_VALUE := SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 6, P_TAG_LEN);
RETURN (DECLARATION_CST.OK);
END IF;
V_COUNTER_LOOP := V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 3, 3));
END LOOP;
RETURN 0;
EXCEPTION
WHEN OTHERS THEN
RETURN -1;
END GET_TAG;
===========================================================
FUNCTION PUT_TAG(P_TAG_NAME IN VARCHAR2, P_TAG_VALUE IN VARCHAR2, P_TLV_STRG IN OUT NOCOPY VARCHAR2)
RETURN PLS_INTEGER IS
V_COUNTER_LOOP PLS_INTEGER := 0;
TMP_VARCHAR VARCHAR2(4096);
BEGIN
P_TLV_STRG := SUBSTR(P_TLV_STRG, 5);
V_COUNTER_LOOP := 1;
WHILE V_COUNTER_LOOP < LENGTH(P_TLV_STRG) LOOP
IF SUBSTR(P_TLV_STRG, V_COUNTER_LOOP, 3) = SUBSTR(P_TAG_NAME, 1, 3) THEN
TMP_VARCHAR :=
SUBSTR(P_TLV_STRG, 1, V_COUNTER_LOOP - 1)
|| SUBSTR(P_TAG_NAME, 1, 3)
|| TO_CHAR(NVL(LENGTH(P_TAG_VALUE), 0), 'FM000')
|| P_TAG_VALUE
|| SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 3, 3)));
P_TLV_STRG := TO_CHAR(LENGTH(TMP_VARCHAR), 'FM0000') || TMP_VARCHAR;
RETURN (DECLARATION_CST.OK);
END IF;
V_COUNTER_LOOP := V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 3, 3));
END LOOP;
P_TLV_STRG :=
P_TLV_STRG
|| SUBSTR(P_TAG_NAME, 1, 3)
|| TO_CHAR(NVL(LENGTH(P_TAG_VALUE), 0), 'FM000')
|| P_TAG_VALUE;
P_TLV_STRG := TO_CHAR(LENGTH(P_TLV_STRG), 'FM0000') || P_TLV_STRG;
RETURN 0;
EXCEPTION
WHEN OTHERS THEN
RETURN -1;
END PUT_TAG;
You need to create the mapping table first in the database which maps to the field and its length (in my example I have used CTE as your mapping table: YOUR_MAPPING_TABLE).
Oracle setup:
SQL> CREATE TABLE TEST1234 (
2 FIELD001 VARCHAR2(4000),
3 FIELD002 VARCHAR2(4000),
4 FIELD003 VARCHAR2(4000),
5 FIELD004 VARCHAR2(4000)
6 );
Table created.
Solution query:
SQL> INSERT INTO TEST1234
2 WITH YOUR_MAPPING_TABLE (FIELD_ID, LEN)
3 AS (
4 SELECT 'FIELD001', 4 FROM DUAL UNION ALL
5 SELECT 'FIELD002', 3 FROM DUAL UNION ALL
6 SELECT 'FIELD003', 3 FROM DUAL UNION ALL
7 SELECT 'FIELD004', 12 FROM DUAL
8 )
9 SELECT * FROM
10 ( SELECT M.FIELD_ID, -- Your string will go in following substring
11 SUBSTR('0086037012123456789012', M.STARTPOS + 1, M.TOTALLEN) AS FIELDVALUE
12 FROM ( SELECT FIELD_ID,
13 SUM(LEN) OVER(ORDER BY FIELD_ID ) - LEN AS STARTPOS,
14 LEN AS TOTALLEN
15 FROM YOUR_MAPPING_TABLE
16 ) M
17 ) PIVOT (
18 MIN ( FIELDVALUE )
19 FOR FIELD_ID IN ( 'FIELD001', 'FIELD002', 'FIELD003', 'FIELD004' )
20 );
1 row created.
Testing the result
SQL> SELECT * FROM TEST1234;
FIELD001 | FIELD002 | FIELD003 | FIELD004
---------- | ---------- | ---------- | -------------
0086 | 037 | 012 | 123456789012
SQL>
You can pass your big string in the query as per your logic.

to call a funktion with a rowtype Parameter

hello everyone i have the following function:
function Entfernung(v_stadt Rheinlandstädte%rowtype)
Return Abstandstabelle is
tabelle ABSTANDSTABELLE;
cursor c_städte IS
Select *
From Rheinlandstädte
;
v_andereStadt Rheinlandstädte%rowtype;
v_entfernung float;
begin
Open c_städte;
LOOP
fetch c_städte into v_andereStadt;
v_entfernung := Abstand(v_stadt, v_andereStadt);
tabelle(v_andereStadt.stadtname) := v_entfernung;
exit when c_städte%NOTFOUND;
END Loop;
close c_städte;
return tabelle;
end Entfernung;
how can i call this function in oracle. The parameter is rowtype and I cant't use SELECT function from DUAL;
A simple example:
SQL> create table tab_par(a number, b number)
2 /
Table created.
SQL> create or replace type tab_numbers as table of number
2 /
Type created.
SQL> create or replace function fun_par (r IN tab_par%rowtype) return tab_numbers is
2 retVal tab_numbers := new tab_numbers();
3 begin
4 retVal.extend(2);
5 retVal(1) := r.a;
6 retVal(2) := r.b;
7 return retVal;
8 end;
9 /
Function created.
SQL> insert into tab_par values ( 10, 5);
1 row created.
SQL> declare
2 r tab_par%rowtype;
3 n tab_numbers;
4 begin
5 select *
6 into r
7 from tab_par
8 where rownum = 1;
9 -- call your function
10 n := fun_par(r);
11 dbms_output.put_line('n = ' || n(1));
12 dbms_output.put_line('n = ' || n(2));
13 end;
14 /
n = 10
n = 5
PL/SQL procedure successfully completed.
SQL>
here is how I call this function, this function is in the package:
DECLARE
v_stadtname_a VARCHAR(20):='Düsseldorf';
v_stadtA Rheinlandstädte%rowtype;
tabelle GEOGRAPHICAL_PACKAGE.ABSTANDSTABELLE;
v_stadt Rheinlandstädte%rowtype;
CURSOR c_sta IS
SELECT * FROM Rheinlandstädte;
BEGIN
SELECT * INTO v_stadtA
FROM rheinlandstädte
WHERE stadtname=v_stadtname_a;
OPEN c_sta;
LOOP
FETCH c_sta INTO v_stadt;
EXIT WHEN c_sta%NOTFOUND;
tabelle := GEOGRAPHICAL_PACKAGE.Entfernung(v_stadtA);
dbms_output.put_line('Abstand zwischen '||v_stadtA.stadtname||' und '||
v_stadt.stadtname||' beträgt: '||tabelle(v_stadt.stadtname)||' km.');
END LOOP;
CLOSE c_sta;
END;

Compare values in each column of two Oracle Types

I've been playing around with the pluto-test-framework today, and I'd like to get some existing functions into a test harness with it.
I have lots of functions with this type of specification.
FUNCTION DO_SOME_STUFF (pOldSchedule IN SCHEDULE_OBJ,
pNewSchedule OUT SCHEDULE_OBJ,
pLoggerContext IN OUT LOGGER_CONTEXT_OBJ)
RETURN NUMBER;
It takes pOldSchedule, does some stuff to it, and then returns pNewSchedule. The logger_context just does logging.
As part of a test, I'd like to be able to compare the values in each of the columns of the type, without having to write individual IF statements.
It'll need to return boolean to signify whether or not pOldSchedule and pNewSchedule match.
Any ideas?
Straightforward equality tests work with nested tables:
SQL> declare
2 type nt is table of number;
3 nt1 nt;
4 nt2 nt;
5 nt3 nt;
6 begin
7 nt1 := nt(1,2,3);
8 nt2 := nt(1,2,3);
9 if nt1 = nt2 then
10 dbms_output.put_line('NT2 is the same nested table as NT1');
11 else
12 dbms_output.put_line('NT2 is a different nested table from NT1');
13 end if;
14 nt2 := nt(1,2,3,4);
15 if nt1 = nt3 then
16 dbms_output.put_line('NT3 is the same nested table as NT1');
17 else
18 dbms_output.put_line('E3 is a different nested table from NT1');
19 end if;
20 end;
21 /
NT2 is the same nested table as NT1
E3 is a different nested table from NT1
PL/SQL procedure successfully completed.
SQL>
However the same is not true of full-on objects:
SQL> create or replace type new_emp as object (
2 ename varchar2(10)
3 , sal number
4 , deptno number
5 , job varchar2(10))
6 /
Type created.
SQL> declare
2 e1 new_emp;
3 e2 new_emp;
4 begin
5 e1 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
6 e2 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
7 if e1 = e2 then
8 dbms_output.put_line('E2 is the same as E1');
9 else
10 dbms_output.put_line('E2 is different from E1');
11 end if;
12 end;
13 /
if e1 = e2 then
*
ERROR at line 7:
ORA-06550: line 7, column 11:
PLS-00526: A MAP or ORDER function is required for comparing objects in PL/SQL.
SQL>
We need to explicitly define a member function for executing comparisons. So here is the same object with a MAP function. The example implementation generates a hashed string, which is useful if we want to store the value for later comparison, but it could just return the concatenated string (especially as EXECUTE on DBMS_CRYPTO is not granted by default). The NVL() functions are necessary to avoid (null, value) and (value, null) being evaluated as equal. There is the always a risk when using magic values, so we need to choose them carefully.
SQL> create or replace type new_emp as object (
2 ename varchar2(10)
3 , sal number
4 , deptno number
5 , job varchar2(10)
6 , map member function equals return raw)
7 /
Type created.
SQL> create or replace type body new_emp as
2 map member function equals return raw
3 is
4 begin
5 return dbms_crypto.hash(
6 utl_raw.cast_to_raw(nvl(self.ename,'***')||
7 nvl(self.sal,-99)||
8 nvl(self.deptno,-99)||
9 nvl(self.job,'***')
10 )
11 , 1);
12 end equals;
13 end;
14 /
Type body created.
SQL>
Now we have a basis for comparing instances of our objects:
SQL> declare
2 e1 new_emp;
3 e2 new_emp;
4 begin
5 e1 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
6 e2 := new_emp('KESTELYN', 3700, 30, 'MARKETING');
7 if e1 = e2 then
8 dbms_output.put_line('E2 is the same as E1');
9 else
10 dbms_output.put_line('E2 is different from E1');
11 end if;
12 end;
13 /
E2 is the same as E1
PL/SQL procedure successfully completed.
SQL>
You might be wondering why Oracle doesn't do this by default. Well, the TYPE implemntation only allows one comparison method (if we have a MAP function we cannot have an ORDER function) so we need to have the capability to choose our own definition of equality. For instance, a type called rectangle might have a MAP function called area() which returns self.width * self.length.

Resources