Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 17, 2020 Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Should a range-compliant aggregate type realizing a parser be encoded as a struct or class? In dmd `Lexer` and `Parser` are both classes. In general how should I reason about whether an aggregate type should be encoded as a struct or class? |
June 17, 2020 Re: Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On Wednesday, 17 June 2020 at 11:50:27 UTC, Per Nordlöw wrote:
> Should a range-compliant aggregate type realizing a parser be encoded as a struct or class? In dmd `Lexer` and `Parser` are both classes.
>
> In general how should I reason about whether an aggregate type should be encoded as a struct or class?
The heuristic I use is 'do I need polymorphism?' If no, it's a struct. Another thing that may be worth considering is reference semantics. The latter is easy to do with a struct, while polymorphism is generally a class-only thing (but check out Tardy, which Atila Neves recently posted in the Announce group).
I would say I basically never use classes in D - pointers and arrays give me all the reference semantics I need, and polymorphism I almost never need.
--
Simen
|
June 17, 2020 Re: Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On Wednesday, 17 June 2020 at 11:50:27 UTC, Per Nordlöw wrote:
> Should a range-compliant aggregate type realizing a parser be encoded as a struct or class? In dmd `Lexer` and `Parser` are both classes.
>
> In general how should I reason about whether an aggregate type should be encoded as a struct or class?
What's a range-compliant aggregate type? Ranges are typically views of someone else's data; an owner of the data woulnd't store mutable iterators, and won't be a range. For that reason also, ranges are structs, as most of them are thin wrappers over a set of iterators with an interface to mutate them.
If you *really* need runtime polymorphism as provided by the language - use a class. Otherwise - use a struct. It's pretty straightforward. Even then, in some cases one can realize their own runtime polymorphism without classes (look at e.g. Atila Neves' 'tardy' library).
It's very easy to implement a lexer as an input range: it'd just be a pointer into a buffer plus some additional iteration data (like line/column position, for example). I.e. a struct. Making it a struct also allows to make it into a forward range, instead of input range, which is useful if you need lookahead:
struct TokenStream
{
this(SourceBuffer source)
{
this.cursor = source.text.ptr;
advance(this);
}
bool empty() const
{
return token.type == TokenType.eof;
}
ref front() return scope const
{
return token;
}
void popFront()
{
switch (token.type)
{
default:
advance(this);
break;
case TokenType.eof:
break;
case TokenType.error:
token.type = TokenType.eof;
token.lexSpan = LexicalSpan(token.lexSpan.end, token.lexSpan.end);
break;
}
}
TokenStream save() const
{
return this;
}
private:
const(char)* cursor;
Location location;
Token token;
}
, where `advance` is implemented as a module private function that actually parses source into next token.
DMD's Lexer/Parser aren't ranges. They're ourobori.
|
June 17, 2020 Re: Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On Wed, Jun 17, 2020 at 11:50:27AM +0000, Per Nordlöw via Digitalmars-d-learn wrote: > Should a range-compliant aggregate type realizing a parser be encoded as a struct or class? Preferably a struct IMO, but see below. > In dmd `Lexer` and `Parser` are both classes. Probably for historical reasons. > In general how should I reason about whether an aggregate type should be encoded as a struct or class? 1) Does it need runtime polymorphism? If it does, use a class. If not, probably a struct. 2) Does it make more sense as a by-value type, or a by-reference type? In several of my projects, for example, I've had aggregate types start out as structs (because of (1)), but eventually rewritten as (final) classes because I started finding myself using `ref` or `&` everywhere to get by-reference semantics. My rule-of-thumb is basically adopted from TDPL: a struct as a "glorified int" with by-value semantics, a class is a more traditional OO object. If my aggregate behaves like a glorified int, then a struct is a good choice. If it behaves more like a traditional OO encapsulated type, then a class is probably the right answer. T -- Many open minds should be closed for repairs. -- K5 user |
June 17, 2020 Re: Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On Wednesday, 17 June 2020 at 11:50:27 UTC, Per Nordlöw wrote:
> Should a range-compliant aggregate type realizing a parser be encoded as a struct or class? In dmd `Lexer` and `Parser` are both classes.
>
> In general how should I reason about whether an aggregate type should be encoded as a struct or class?
I would say a struct.
Parser in dmd does even inherit from Lexer.
It seems to be a quirky design.
Especially for multi-threaded parsing you might want to have more control over memory layout than classes usually give you.
|
June 17, 2020 Re: Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stefan Koch | On Wednesday, 17 June 2020 at 14:24:01 UTC, Stefan Koch wrote:
> Parser in dmd does even inherit from Lexer.
why would a parser ever inherit from a lexer?
|
June 17, 2020 Re: Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Wed, Jun 17, 2020 at 02:32:09PM +0000, Adam D. Ruppe via Digitalmars-d-learn wrote: > On Wednesday, 17 June 2020 at 14:24:01 UTC, Stefan Koch wrote: > > Parser in dmd does even inherit from Lexer. > > why would a parser ever inherit from a lexer? Because, unlike a regular parser-driven compiler, dmd is a lexer-driven one. :-D T -- The volume of a pizza of thickness a and radius z can be described by the following formula: pi zz a. -- Wouter Verhelst |
June 18, 2020 Re: Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Per Nordlöw | On Wednesday, 17 June 2020 at 11:50:27 UTC, Per Nordlöw wrote: > Should a range-compliant aggregate type realizing a parser be encoded as a struct or class? In dmd `Lexer` and `Parser` are both classes. > > In general how should I reason about whether an aggregate type should be encoded as a struct or class? You have the example of libdparse that shows that using a class can be a good idea [1] [2]. For DCD, the parser overrides a few thing because otherwise completion does not work properly or has scope issues. But TBH there's not many reasons to use a class otherwise. [1] https://github.com/dlang-community/dsymbol/blob/master/src/dsymbol/conversion/package.d#L102 [2] https://github.com/dlang-community/dsymbol/blob/master/src/dsymbol/conversion/package.d#L138 |
June 18, 2020 Re: Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Wednesday, 17 June 2020 at 14:32:09 UTC, Adam D. Ruppe wrote:
> On Wednesday, 17 June 2020 at 14:24:01 UTC, Stefan Koch wrote:
>> Parser in dmd does even inherit from Lexer.
>
> why would a parser ever inherit from a lexer?
So you can write nextToken() instead of lexer.nextToken()
|
June 18, 2020 Re: Should a parser type be a struct or class? | ||||
---|---|---|---|---|
| ||||
Posted in reply to welkam | Oh an also https://github.com/dlang/dmd/pull/9899 |
Copyright © 1999-2021 by the D Language Foundation