Problems with user defined types

Help requests on developing Logtalk applications

Moderator: Paulo Moura

Post Reply
kaiser185
Posts: 5
Joined: Sun Oct 04, 2020 10:27 pm

Problems with user defined types

Post by kaiser185 »

Hello Mr. Moura,

I hope you are well. I write this because I have been trying to implement user-defined types within my application, but I seem to be running into trouble getting it work, and am also observing some strange behaviour, which I would hope you could help shed some light on, or perhaps point me in the right direction to be able to solve it. Here is the code I have implemented for these tests (the underlying prolog engine is SWI, if that helps):

Code: Select all

:- category(my_types).

	% register a new parametric temperature type
	:- multifile(type::type/1).
	type::type(attackPlan).
	type::type(attackAction).
	type::type(asset).

	% add the actual checking code for the new type
	:- multifile(type::check/2).
	type::check(attackPlan, _P_) :-
		check_attackPlan(_P_).
	type::check(attackAction, _P_) :-
		check_attackAction(_P_).
	type::check(asset, _P_) :-
		check_asset(_P_).
	
	check_attackAction(_P_) :-
		_{risk:Risk, asset:Asset, impact:Impact, type:Type} :< _P_,
		type::check(integer, Risk),
		type::check(integer, Impact),
		type::check(atomic, Type),
		type::check(asset, Asset).
	
	check_attackPlan(_P_) :-
		_{a:AAs} :< _P_,
		type::check(property(list, [AttackActions]>>(
			meta::map([AA]>>(
				type::check(attackAction, AA)	
			), AttackActions)	
		)), AAs).

	check_asset(_P_) :-
		_{id:Id, os:OS, ip:IP} :< _P_,
		meta::map([Attr]>>(type::check(atomic, Attr)), [Id, OS, IP]).

:- end_category.
Concretely the issue I observe is the following: when I run the query below it fails silently, but, and that is what is strange, if I run the same predicate with the debugger enable, with:

Code: Select all

debugger::trace
When running it in this way it does not fail, with exactly the same input.

Code: Select all

?- R = _{a:[                                                                                                                                                                           
_{impact:5, risk:50, asset:_{id:"1", os:"linux", ip:"1.1.1.1"}, type:"dos", id:"1"},
_{impact:5, risk:50, asset:_{id:"2", os:"linux", ip:"1.1.1.2"}, type:"malware", id:"2"},                                    
_{impact:5, risk:50, asset:_{id:"3", os:"linux", ip:"1.1.1.3"}, type:"dos", id:"3"},                                                                                                   
_{impact:5, risk:50, asset:_{id:"4", os:"linux", ip:"1.1.1.4"}, type:"malware", id:"4"},                                                                                               
_{impact:5, risk:50, asset:_{id:"5", os:"linux", ip:"1.1.1.5"}, type:"networkRecon", id:"5"},                                                                                          
_{impact:5, risk:50, asset:_{id:"6", os:"linux", ip:"1.1.1.6"}, type:"networkRecon", id:"6"}                                                                                           
]}, 
type::check(attackPlan, R).
Furthermore, I would like to know if this may perhaps be caused by the use of SWI specific dict terms (which do have some special properties). Please do let me know if you need any more information on my part.

Thank you very much for your time.

-K

P.S. I have also been using Logtalk's VSCode extension, which, when analyzing its source code, it seems to be using the logtalk compiler (the swilgt executable) to perform linting on the files, however the linter seems to find a permission error when defining the multifile predicates as it says the type object is not modfiable:

Code: Select all

type::type/1
type::check/1
Running this through even the example from your github repository : https://github.com/LogtalkDotOrg/logtal ... _types.lgt, it gives the same error, though I am unsure why that is as I very much doubt that the example is wrong in any way. Do you have any idea why this may be the case and how one could mitigate this (as the extension is enormously helpful when developing).

Paulo Moura
Logtalk developer
Posts: 531
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Problems with user defined types

Post by Paulo Moura »

I'm unable to reproduce the problem. The query works for me outside the debugger:

Code: Select all

?- {types(loader), meta(loader), my_types}.
...
% (0 warnings)
true.

?- R = _{a:[
_{impact:5, risk:50, asset:_{id:"1", os:"linux", ip:"1.1.1.1"}, type:"dos", id:"1"},
_{impact:5, risk:50, asset:_{id:"2", os:"linux", ip:"1.1.1.2"}, type:"malware", id:"2"},
_{impact:5, risk:50, asset:_{id:"3", os:"linux", ip:"1.1.1.3"}, type:"dos", id:"3"},
_{impact:5, risk:50, asset:_{id:"4", os:"linux", ip:"1.1.1.4"}, type:"malware", id:"4"},
_{impact:5, risk:50, asset:_{id:"5", os:"linux", ip:"1.1.1.5"}, type:"networkRecon", id:"5"},
_{impact:5, risk:50, asset:_{id:"6", os:"linux", ip:"1.1.1.6"}, type:"networkRecon", id:"6"}
]},
type::check(attackPlan, R).
R = _46182{a:[_46204{asset:_46226{id:"1", ip:"1.1.1.1", os:"linux"}, id:"1", impact:5, risk:50, type:"dos"}, _46248{asset:_46270{id:"2", ip:"1.1.1.2", os:"linux"}, id:"2", impact:5, risk:50, type:"malware"}, _46292{asset:_46314{id:"3", ip:"1.1.1.3", os:"linux"}, id:"3", impact:5, risk:50, type:"dos"}, _46336{asset:_46358{id:"4", ip:"1.1.1.4", os:"linux"}, id:"4", impact:5, risk:50, type:"malware"}, _46380{asset:_46402{id:"5", ip:"1.1.1.5", os:"linux"}, id:"5", impact:5, risk:50, type:"networkRecon"}, _46424{asset:_46446{id:"6", ip:"1.1.1.6", os:"linux"}, id:"6", impact:5, risk:50, type:"networkRecon"}]}.
For reference, I'm using SWI-Prolog 8.3.11 and the current Logtalk git version.
Paulo Moura
Logtalk developer

kaiser185
Posts: 5
Joined: Sun Oct 04, 2020 10:27 pm

Re: Problems with user defined types

Post by kaiser185 »

Hello, I seem to have isolated the exact combination of loaded libraries that produce this behaviour, here is the loader file with which I observe said behaviour:

Code: Select all

:- initialization((
	logtalk_load([ 
		meta(loader),
		types(loader), 
		debugger(loader),
		my_types
	], [debug(on)])
)).
From what I can tell, either removing the debugger(loader) line, or the debug(on) option seems to fix the problem. Do you observe this on your end as well with this loader file? Am I making some beginner mistake through the combination of debugger(loader) and debug(on) ?

Thank you.

Paulo Moura
Logtalk developer
Posts: 531
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Problems with user defined types

Post by Paulo Moura »

The debug(on) option is only affecting the compilation of the "my_types" source file. It also affects the compilation of the loader files themselves for libraries and tools but not the actual source files loaded by the loader files. I.e. the "my_types" category is the only entity compiled in debug mode. Nothing wrong in your loader file.

Doing what your loader does, I do get a failure for your test query. Given that SWI-Prolog implementation of dicts uses its term-expansion mechanism, is possible that the wrapping introduced by compiling in debug mode prevents the used expansion rules to act in all code places that are required. That would explain why the query works when compiling in normal (and, I assume, optimized mode).
Paulo Moura
Logtalk developer

kaiser185
Posts: 5
Joined: Sun Oct 04, 2020 10:27 pm

Re: Problems with user defined types

Post by kaiser185 »

Thank you for your prompt reply!

From what you say I gather that there may be some interoperability issues between SWI and Logtalk that might impede the use of such constructs for type checking and definition. Did I understand correctly? Do you have any suggestions as to how I may go about combatting this, or is it something that can't be fixed (meaning It'll be best to seek out some alternative to the use of dicts with the type system)?

Paulo Moura
Logtalk developer
Posts: 531
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Problems with user defined types

Post by Paulo Moura »

A know incompatibility is due to the use of SWI-Prolog eager evaluation of dict functions, which can result in errors due to arguments only know at runtime. No workaround exists currently. There are likely others such as the one that's causing the issue you report. For code portability, proprietary constructs such as SWI-Prolog dicts should be avoided. An alternative could be to use compound terms where arguments can be compound terms themselves (e.g. structure(..., asset(Id,OS,IP), ...). This alternative also have the potential of being more efficient (e.g. you can simply use arg/3 to access an argument such as asset/3) although possible a bit more cumbersome to access and use.
Paulo Moura
Logtalk developer

kaiser185
Posts: 5
Joined: Sun Oct 04, 2020 10:27 pm

Re: Problems with user defined types

Post by kaiser185 »

I understand, I'll try to see if I can find a compromise that preserves the dicts' ease of use whilst maintaining Logtalk-friendliness. Thank you very much for your time and prompt responses, they were most instructive.

kaiser185
Posts: 5
Joined: Sun Oct 04, 2020 10:27 pm

Re: Problems with user defined types

Post by kaiser185 »

Hello again Mr. Moura,

I have tried to apply the technique you suggested, using compound terms instead of dicts for the custom types, but I seem to continue to encounter the same issue as before.

I have prepared a github gist that both includes the code necessary to reproduce the bug and the loader files (plus a comment detailing how exactly to make the bug manifest itself), which you can find at: https://gist.github.com/kaiser185/5462f ... 247a86f5f9. I've taken care to avoid, as much as possible any SWI-Prolog specific feature in the code, so hopefully it does not emanate from Logtalk's interaction with SWI's own mechanisms.

Please let me know if you are able to reproduce this behaviour on your end. Thank you again for your time.

-K

Paulo Moura
Logtalk developer
Posts: 531
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Problems with user defined types

Post by Paulo Moura »

Fixed in the current Logtalk git version:

https://github.com/LogtalkDotOrg/logtal ... 0a6be0d0f4

Thanks for reporting.

P.S. In the loader file, there's no point in trying to compile the "meta", "types", and "debugger" libraries in debug mode as their loader files override the debug mode and compile the code in optimal mode.
Paulo Moura
Logtalk developer

Post Reply