1. will map:put() never fail?

Shouldn't map:put() be a function in case it needs to report an error? I don't see anything like "map:get_error()" either...

Or maybe map:put() will never fail?

new topic     » topic index » view message » categorize

2. Re: will map:put() never fail?

euphoric said...

Shouldn't map:put() be a function in case it needs to report an error? I don't see anything like "map:get_error()" either...

Or maybe map:put() will never fail?

The only failure mode I could think of would be if you passed an invalid map, which would result in a crash. What sort of error are you expecting?

Matt

new topic     » goto parent     » topic index » view message » categorize

3. Re: will map:put() never fail?

mattlewis said...
euphoric said...

Shouldn't map:put() be a function in case it needs to report an error? I don't see anything like "map:get_error()" either...

Or maybe map:put() will never fail?

The only failure mode I could think of would be if you passed an invalid map, which would result in a crash. What sort of error are you expecting?

No expectations, just ignorance. If, for some reason, map:put() cannot complete the put(), I would like to know about it. But, if map:put() will never fail, then no biggie.

A SUCCESS or FAIL result would be enough (for now).

new topic     » goto parent     » topic index » view message » categorize

4. Re: will map:put() never fail?

euphoric said...

Shouldn't map:put() be a function in case it needs to report an error? I don't see anything like "map:get_error()" either...

Or maybe map:put() will never fail?

It can fail, but if it does it causes a program fail too. It can fail for these reasons ...

  1. The MAP ID is wrong. Either an invalid value or it refers to an object which isn't a map.
  2. The OPERATION argument is not a valid value.
  3. The OPERATION argument is invalid for the case when the KEY does not exist in the map.
  4. The computer's RAM has been exhausted.


I think that the idea was that if one of these situations arose, then the application is already compromised and cannot continue anyhow.

new topic     » goto parent     » topic index » view message » categorize

5. Re: will map:put() never fail?

DerekParnell said...
euphoric said...

Shouldn't map:put() be a function in case it needs to report an error? I don't see anything like "map:get_error()" either...

Or maybe map:put() will never fail?

It can fail, but if it does it causes a program fail too. It can fail for these reasons ...

  1. The MAP ID is wrong. Either an invalid value or it refers to an object which isn't a map.
  2. The OPERATION argument is not a valid value.
  3. The OPERATION argument is invalid for the case when the KEY does not exist in the map.
  4. The computer's RAM has been exhausted.


I think that the idea was that if one of these situations arose, then the application is already compromised and cannot continue anyhow.

  1. We should return BAD_MAP_ID (-1)
  2. We should return BAD_OPERATION_VALUE (-2)
  3. We should return KEY_DOES_NOT_EXIST (-3)
  4. We should return OUT_OF_MEMORY (-4), if possible

Otherwise, we return 1 (SUCCESS!).

It could STILL be used as a procedure, because 4.x does not require you to use the return value. So it won't break code if we turn this into a function.

OR, we could put it on the user to test for all those things first, which is not very nice. :)

new topic     » goto parent     » topic index » view message » categorize

6. Re: will map:put() never fail?

I prefer the method it currently uses. For example:

map m = map:new() 
sequence name = "John" 
 
map:put(name, "age", 22) 

is an exceptional problem. It is a programming error and one cannot recover from it by checking the return result. The proper thing to do is an application crash. If it fails because of memory, your app is going to fail regardless. If it fails because you pass a bad operation:

map:put(name, "age", 22, 192839283) 

then it's a programming error and it cannot be recovered from by checking an error return value. It's better to fail early than late. Failing late only obscures the real problem. It's also better to check ALL function returns. By turning an exceptional error into a passable situation, you introduce errors into everyones code. If the routine is going to pass 99.9% of the time, who is going to check the return result with every call to that routine? No one. That would lead to horrid code as well:

if map:put(name, "age", 22) != map:SUCCESS then 
    error() 
end if 
if map:put(name, "city", "Smalltown") != map:SUCCESS then 
    error() 
end if 
if map:put(...) then 
    .... 
end if 

Now, number 3 in Dereks list is pretty debatable.

DerekParnell said...

3. The OPERATION argument is invalid for the case when the KEY does not exist in the map.

For that, an error code result actually makes sense, but one can handle this a bit differently and save the terrible coding techique given above. They can do it by:

if not map:has(my_map, "name") then 
    map:put(my_map, "age", 100) 
else 
    map:put(my_map, "age", 4, map:DIVIDE) 
end if  

Thus, you have provided a solution for the potential failure of map:put() w/o having to fall back on checking the errror result. Now, the code may be slightly better if map:put returned an error code in this condition, ONLY IF the majority of the iterations you are doing a divide operation:

if map:put(my_map, "age", 4, map:DIVIDE) != map:SUCCESS then 
    map:put(my_map, "age", 100) 
end if 

but that is only a good case if you know the majority of the time age already exists. Not sure that warrants an error return value when a valid method exists for avoiding it.

Jeremy

new topic     » goto parent     » topic index » view message » categorize

7. Re: will map:put() never fail?

euphoric said...

OR, we could put it on the user to test for all those things first, which is not very nice. :)

This is a question that has been argued and discussed since the dawn of programming. It boils down to where do we want to make the trade-off point. The trade-off is between application reliability and application performance. The more that low-level routines examine input arguments for validity the slower an application runs.

Another consideration is that the fact that a routine returns a success/failure code does not necessarily increase application reliability, unless the application chooses to test the routine's result. So it is quite possible to have a routine expend time testing argument correctness only to have the calling process either not test the result or get that testing wrong anyhow.

In this case, nearly all calls to the put() routine will be passed correct arguments and thus having the routine itself examine them for correctness is mostly going to be a waste of time. If your application requires greater reliability than this assumption, then maybe your application should take on the responsibility of argument validation.

A further complication in this particular case is that the some of the current error conditions are tested for free. The testing for a bad OPERATION argument adds no real performance hit, and and out-of-RAM error will crash your application even if put() explicitly tested for that anyway. The only one that could add some performance penalty is having put() test for a valid MAP ID, but you can simply test for this before invoking significant put() calls ...

if map(someid) then 
    put(someid, ... ) 
end if 
new topic     » goto parent     » topic index » view message » categorize

8. Re: will map:put() never fail?

euphoric said...

Shouldn't map:put() be a function in case it needs to report an error?

I just had another thought ... very soon I expect that we will add exceptions to Euphoria and that means then that applications can trap certain or all exceptions and handle them in specific ways.

new topic     » goto parent     » topic index » view message » categorize

9. Re: will map:put() never fail?

Some doubts about map.e

This is from load_map in in std:map.e, lines 1531-1670. This code is intended to load key, value pairs from a text file into a hash-map.

The structure of a key value pair is:

key = value <nl>

Line continuation characters are `,`, `$` and `{`. `",$\n"` concatenates strings, `,$` joins lines removing the `,$` Comments are allowed anywhere.

 1 while sequence(logical_line) with entry do 
 2   delim_pos = find('=', logical_line) 
 3   if delim_pos > 0 then 
 4 	 data_key = text:trim(logical_line[1..delim_pos-1]) 
 5 	 if length(data_key) > 0 then  = 
 6  	   data_key = search:match_replace("\\-", data_key, "-") 
 7 		if not t_alpha(data_key[1]) then 
 8		     conv_res = stdget:value(data_key,,stdget:GET_LONG_ANSWER) 
 9 		  if conv_res[1] = stdget:GET_SUCCESS then 
10 			 if conv_res[3] = length(data_key) then 
11 				data_key = conv_res[2] 
12 			 end if 
13 		  end if 
14 		end if 
15 		data_value = text:trim(logical_line[delim_pos+1..$]) 
16 		data_value = search:match_replace("\\-", data_value, "-") 
17 		conv_res = stdget:value(data_value,,stdget:GET_LONG_ANSWER) 
18 		if conv_res[1] = stdget:GET_SUCCESS then 
19 		  if conv_res[3] = length(data_value) then 
20 			 data_value = conv_res[2] 
21 		  end if 
22 		end if 
23 		put(new_map, data_key, data_value) 
24 	 end if 
25   end if 
26 entry 
27   logical_line = -1 
28   while sequence(line_in) with entry do 
29 	 if atom(logical_line) then 
30 		logical_line = "" 
31 	 end if 
32 	 has_comment = search:rmatch("--", line_in) 
33     if has_comment != 0 then 
34       line_in = text:trim(line_in[1..has_comment-1]) 
35     else 
36       line_in = text:trim(line_in) 
37     end if 
38     logical_line &= line_in 
39     if length(line_in) then 
40       if not find(line_in[$], line_conts) then 
41 		  logical_line = search:match_replace(`",$"`, logical_line, "") 
42 		  logical_line = search:match_replace(`,$`, logical_line, "") 
43 		  exit 
44       end if 
45     end if 
46   entry 
47     line_in = gets(file_handle) 
48   end while 
49 end while 

Take the section from line 26 to the end.

What is intended is *something like:

  ---------------------------- 
  read a line in 
  remove comments and trim 
  redo if the line is blank 
  while the line has a continuation 
	 read a line in 
	 remove comments and trim 
	 append 
  end while 
  remove characters as needed 
  return to the main loop 

Errors:

1 Line 32 assumes -- cannot appear in a comment, or a quoted string

2 Line 2 assumes = will not appear in a quoted string

3 Lines 41,42 remove ",$" ,$ globally in the line

4 Blank lines are completely ignored - so blank lines after a continuation will be ignored and the next non-blank line appended.

5 The inner loop is not entered at end of file. If a line was incomplete at EOF then it would not be properly processed.

6 Lines 3 and 5 ignore lines without a key.

7 Sequence constructors are allowed in the line but no attempt is made to check their validity.

8 All lines are valid as they are read in as text.

new topic     » goto parent     » topic index » view message » categorize

10. Re: will map:put() never fail?

bill said...

Some doubts about map.e

Good call. I'll repair these (and others) and introduce much more vigorous unit tests.

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu