Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re^2: [DSL] disabling packages in Perl? (meditation)

by LanX (Saint)
on Apr 19, 2016 at 12:55 UTC ( [id://1160885]=note: print w/replies, xml ) Need Help??


in reply to Re: [DSL] disabling packages in Perl? (updated)
in thread [DSL] disabling packages in Perl?

Thanks a lot ... unfortunately I'm too busy like now to test it all out or elaborate much further.

> I imagine that packages named IN and LIKE are unlikely to clash with other packages...

That's true but I'm looking for a general "solution" ...

> Also, by "disabling", do you mean actually undefining the methods, or just setting a flag such that they fail when called outside of the appropriate scope (whichever one that is)?

hmm good question...

Ideally I'd like to be able to attach a "domain" to a code block to automatically have package and uses prepended, something like

sub SQL(&) :prepend('package mySQL; use DSL::mySQL;') { ... }

and whenever I execute

SQL { SELECT {} FROM {} WHERE {} }

then the code block is already parsed with methods imported from DSL::SQL which are not visible outside of the code block. OTOH variables from the outer scope would be visible inside the inner scope.

some background¹ ...

I'm meditating about internal DSLs ("Domain Specific Languages") and ideally a "sub language" could be included adding new "syntax" (or better phrased syntactic sugar) not leaking to the outer scope.

Traditionally we often use outer DSLs defined in strings/files which need to be parsed and evaluated. Take for instance a template system like TT.

CGI.pm used to have an inner DSL to build HTML, there is also Jade for HTML in JS or LINQ for SQL in .NET .

Cheers Rolf
(addicted to the Perl Programming Language and ☆☆☆☆ :)
Je suis Charlie!

¹) well this should better be in the meditation section ...

Replies are listed 'Best First'.
Re^3: [DSL] disabling packages in Perl? (meditation)
by haukex (Archbishop) on Apr 23, 2016 at 20:28 UTC

    Hi Rolf,

    I've finally had some time to think about this some more. I don't think there's a clear answer here, but I've included some sample code in which I've experimented with a few things.

    I realized that automatically switching packages inside an SQL { ... } block might not be such a good idea, because it breaks something as simple as sub get_value { ... }; SQL { xyz LIKE get_value() };. So instead, it might make sense to use a module or a pragma that is only effective in its lexical scope, i.e. SQL { use SQL_DSL; ...; no SQL_DSL; }.

    I agree that %^H does not seem to be useful to have something "unimported" or "undefined" at the end of a scope, it could only disable the functions like in my version "one" above. However, there is B::Hooks::EndOfScope, which is used by all three namespace::clean, namespace::autoclean and namespace::sweep! Or, one of the two methods above (pluggable keywords or source filters) could theoretically be used to insert a no statement at the end of the block. However, the problem that does remain is that these two methods are not particularly robust.

    I haven't yet come up with any better ways to enable and disable syntactical features in a certain lexical scope at compile time without reaching into the internals (then again I'm not that much of an expert, so I could be missing something - I did run across Devel::Declare but haven't had a chance to look at it more closely*). It might be possible to define your DSL in a way that a SQL { ... } block complies cleanly, and then the features used within it are only enabled at run time (sub SQL (&) { enable_features(); shift->(); disable_features(); }), but that might be too limited. On the other hand, if you're trying to add syntactic sugar that goes too far beyond what Perl can do natively, you're essentially defining a mini-language that extends Perl. And if you don't want to slap a source filter around your whole program, the simplest solution might be: sub SQL ($) { ... };  SQL q{ WHERE b LIKE %abc% };

    A lot of the above thoughts are more about the technical "how" than the "why" or "what for". Of course a lot depends on what you want your DSL to look like and what you want it to do. For SQL, there's already SQL::Abstract and SQL::Statement, or perhaps, as you mentioned elsewhere in this thread, you want something more like CGI's HTML generation statements, select(from(...),where(like('b','%abc%'))...

    Anyways, that's just some more thoughts on the matter, maybe it helps!

    Regards,
    -- Hauke D

    * Update: From the documentation of MooseX::Declare:

    Warning: MooseX::Declare is based on Devel::Declare, a giant bag of crack originally implemented by mst with the goal of upsetting the perl core developers so much by its very existence that they implemented proper keyword handling in the core.

    As of perl5 version 14, this goal has been achieved, and modules such as Devel::CallParser, Function::Parameters, and Keyword::Simple provide mechanisms to mangle perl syntax that don't require hallucinogenic drugs to interpret the error messages they produce.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1160885]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (7)
As of 2024-04-19 09:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found