-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
custom / __tostring printer results incorrectly put into quotes #10
Comments
I'd say that Maybe |
@agladysh Adding this produces the same result:
Besides, it could be debatable whether this is a bug for |
@fab13n, I agree, it may make sense to handle Is it be sufficient for your purposes if |
I think
Sure, the version with mandatory quotes is valid Lua, but a valid Lua that's semantically different from the original one. It's arguably more treacherous, rather than safer. If users want to add quotes, they can add them in their As for using serialization instead of pretty-printing when one intends to pretty-print in a prettier way, I find this rather confusing :-) Besides, I don't even know whether I can use readability-improving options, such as indentation, with |
Yes, I do see this point and has struggled with the same considerations in the beginning. The main goal was to make the output consistent between serialization and pretty-printing as it's convenient in many situations take the "printed" output and paste it into a script. For example, when you use a console in the IDE to execute commands, is the result serialization or pretty-printing? It's probably mostly the latter, but I've seen on several occasions people taking the output from the console and pasting it into their code.
Right, but these are different values and I wanted them to look different. Similar to that, there is ambiguity with I can add a parameter to disable quoting of string values and would prefer keep the current option as the default. |
On Mon, Dec 30, 2013 at 7:01 PM, Paul Kulchenko [email protected]:
|
I understand, but they only look the same because your There is still a difference between: function token_mt :__tostring() return "true" end
-- and
function token_mt :__tostring() return true end I pushed a change (in print(s.block(stream, {rawstring = true}))
-- generates
{
token(Keyword, local),
token(Id, x)
} --[[table: 00C8C248]] You can make it a default for all methods, so that your users don't need to specify it. Will this work? |
I'm not sure if this is a correct approach. I think this should be configurable on per-object level. It makes little sense to me to configure a thing like this once per serialization call. |
I thought so as well; for example, adding something like |
There is yet another use-case for pretty-printing while serializing — human-readable config files. This is a primary reason why in Lua Núcleo we have So, we have at least three reasons to convert a Lua object to string:
Human-readable serialization and visualization should be highly configurable to conform to usage modes (single-line logging, multi-line config files) and to coding guidelines (indentation rules, line width etc.) |
Maybe I'm missing something (didn't study serpent design too close yet, sorry), but I'm not sure why I'd start with Then I'd consider enabling To me |
Furthermore, all this metamethod handling is a sugar that will slow down the basic implementation. Why not leave it to user to sort out in a custom serialization callback function? (Well, OK, and maybe provide some useful common implementations in an auxiliary module...) |
Please don't use such generic names to control module-specific behaviour. If you really want a flag, use |
BTW, while we're considering When I'm serializing to an output stream (say, |
This is the same thing that serpent does with different methods and options it provides. Using per-object configuration allows one to mix objects with different configurations in one serialization call, although I'm not sure how useful it is.
Yes, serpent also supports all these combinations except limiting line width.
This is a good point; it should be possible to write a wrapper around serpent that will allow "pulling" of the next token, allowing to do whatever desired with it and limiting memory use to the token being returned. @fab13n, if you prefer not to add the |
Is this hard to implement? |
No, but it hasn't been a popular feature so far. Also, the original goal for Serpent was to provide "good enough" implementation (in the sense of "good" correctness and "enough" features for majority of users), while still staying small. It's not so small anymore, but I'm hesitant to add features "just in case". I usually look for specific use cases or user requests. |
BTW, there is yet another use-case "axis" for human-readable part — fast and good-enough vs. slow and really nice-looking. When I'm writing data to a log file, I need it to be human-readable, but I need to write it really fast, even at expense of certain features ( When I'm generating code (like a configuration file), I need to do it prettily and I do not care for the speed (as much): Interestingly enough, |
I'm considering dropping |
That's good as a feature request ;). Good point on fast vs. pretty, although it's difficult to say ahead of time what features can be skipped to make things fast(er). |
Well, to me I see several major use-cases (examples in pseudocode, I've actually needed everything listed here at one time or another):
Not a single use-case that I see now requires non-raw pasting. What am I missing? |
Furthermore, (I also updated the post above a bit.) |
Item 3 above also may include custom field order for an object, BTW, — useful for DSLs, where field order may be determined by the purpose of the field (say, first common fields, then specialized for this specific construct), thus be dependent on |
(Edited that big post with use-cases again.) |
...And here is a problem with using a metamethod instead of a callback in serialization. Generally, you want to save the object in such way that, when loaded back, it will be able to save itself again. This means that this doesn't cut the mustard:
You always need a constructor that will set a metatable:
This is not a problem for visualization — you don't need to load anything back. But for serialization you're better off using a callback function. This way you would not need to set any metatables on load, and can just emit good old table literals. |
It's actually something that many users find useful/helpful. Some use it for their own values that already provide __tostring (pkulchenko/ZeroBraneStudio#77) and some use it to serialize and print their userdata (for example, Marmalade Quick).
That's a lot to review and digest; thank you for the summary. What's |
|
The usage of the True, in certain closed ecosystems it is possible to institute a stricter contract. But in general, IMO, a serialization code should not look at Visualization is debatable. But, if I were writing a debugger, I would, first of all, provide my own callback, so users could specialize their code. Besides, what if |
That's what I suspected, but I thought you were arguing against adding metamethods to all the objects: "If I'm using serpent for serialization, I must add __serialize to every object that might have __tostring in its metatable — even on a object from foreign module." It seems like there are three main options for implementing that:
|
(BTW, please don't let my ramblings to distract you from giving Fabien a working solution for his immediate problem :-) We can discuss theory for ever, but it is practice that is important.) |
In what way? This is not too different from using |
This was an argument against |
;). I'll give Fabien a chance to respond to all the suggestions we discussed... |
If we're talking about serpent-specific callbacks, having a 'custom' option I still believe that forcing quotes around tostring results is wrong, but I
|
So, what I have in the rawstring branch would then work for you? print(s.block(stream, {rawstring = true}))
-- generates
{
token(Keyword, local),
token(Id, x)
} --[[table: 00C8C248]] |
Come to think about it, there is a catch here. Downside of a callback function is that it is centralized — and forces tight code coupling. If your objects come from different modules, you have to be aware of each one of them in the callback. Now you do dispatch by metamethods, which is nice when you have a metatable. And you often do, actually, when serializing a complex object, — despite what I said earlier. So, it is probably better to keep supporting metamethod dispatch. The argument against metamethods comes from the use-case when I don't have a "natural" metatable on the object and don't want to add it — DSL-ization of the data (see use-cases 1-3 above). I do my dispatch by the For that use-case a centralized callback function is OK, I can just skip metamethods altogether. However, in general my object factories do not use metatables too, unless it is absolutely necessarily, — in plain Lua 5.1 it is usually faster to manually fill a table with methods than to call So, for example, what if I want to put my serialization code to the This is getting a bit contrived though... |
Don't know about others, but I wouldn't intentionally call Anyway, a good debugger, IMHO, does not have any right to affect the value that is being inspected in any way without explicit user command. What if I'm debugging
To be even more realistic, what if A debugger does not have a right to assume that |
My use-case is handled adequately by One design consideration, though: |
@fab13n sure, __serpent is tight coupling. But I do not see how it can be avoided — unless you happen to invent a generic API somehow. Serialization of complex business-logic object is a complicated and messy business. If you want it to be performance-effective, you must use advanced features, which almost always are specific to the serialization library. Look at how many use cases we listed above. Most need their own API. Add to the mix low level data formats (i.e. JSON instead of Lua), format versioning and support for older versions and all other stuff — and you'll see why I say that And |
I'm evaluating the feasibility of using Serpent as Metalua's pretty-printer. I'm stuck with the fact that the result of __tostring metamethods are put into quotes. There's a similar issue with custom printers. For instance:
The text was updated successfully, but these errors were encountered: