Different functions for filled and outlined shapes

Issue #678 wontfix
created an issue

There are two issues with how things are at the moment:

  • The draw mode for shapes has to be specified all the time.
  • The draw mode is mixed in with the conceptually distinct geometry information, except with lines.

My proposal to fix these is to have different functions for filled and outlined shapes:

love.graphics.arc( x, y, radius, angle1, angle2, segments )
love.graphics.arcLine( x, y, radius, angle1, angle2, segments )
love.graphics.circle( x, y, radius, segments )
love.graphics.circleLine( x, y, radius, segments )
love.graphics.rectangle( x, y, width, height )
love.graphics.rectangleLine( x, y, width, height )
love.graphics.polygon( vertices )
love.graphics.polygonLine( vertices )
love.graphics.line( points )

Additional benefits are:

  • There are less characters to type.
  • It avoids the use of an enum. Using an enum, you have to be aware of what other values the enum can have. Here, the information is in the function name.
  • Consistency of some sort. To the best of my knowledge, no other function which takes an argument to change the "style" of the function has such an argument without a default. (See love.audio.newSource, Source:seek, love.filesystem.newFileData, etc.)

The only drawback I can see is that there are simply more functions. But, I think they result in a net decrease of complexity.

Comments (10)

  1. criptych

    I've used APIs with a similar convention and rather liked it. What about using "drawX" and "fillX" for lines and fills, respectively? This would echo the generic "draw" function and match the use of verbs as function names throughout most of LOVE.

    If I'm not mistaken, dropping the enum may also help performance, but only slightly.

  2. hahawoo reporter

    That's cool that it's used successfully elsewhere. And it's an interesting observation about verbs as function names, I hadn't thought of that.

    An issue with drawX and fillX though might be that fillX functions would be the only functions which drew something to the screen and didn't start with draw (Edit: Actually that's not right, print and printf don't start with draw either). I guess it could be drawFilledX, but that's getting a bit too long. Alternatively it could be drawX and drawXLine. But I'm still a fan of X and XLine, just because I like the primitives being concise.

  3. hahawoo reporter

    The problem I see with strokeShape and fillShape is that the verbs don't really say what they do, for example strokeCircle doesn't "stroke a circle". Well... maybe it does? I dunno, just seems slightly strange to me at the moment.

    drawStrokedCircle or drawOutlinedCircle or drawCircleLine seem to say what they do more accurately, I think, maybe, to me.

    The word "stroke" and verbs (stroke/fillShape) are inconsistent with love.graphics.line, which uses the word "line" and is a noun. I guess strokeLine would be possible?

    I'm still a fan of the nouns shape and shapeLine though. It's a good point that most LÖVE functions are verbs, but to note, not all are:


    They could be made into verbs though:

    love.graphics.goToOrigin -- Something better than this. :D

    Still, I'm not sure whether this consistency would be worth it.

  4. hahawoo reporter



    To quote from Bret Victor's Learnable Programming:

    This example assumed a hypothetical graphics library which was designed for autocomplete -- all of the drawing functions begin with "draw", so the completion list would appear as the designer intended.*

    * Strangely, I don't actually know of any APIs that are intentionally designed with autocomplete in mind. I do know many APIs, such as Processing, that are designed for brevity, which is irrelevant in an environment with good autocomplete.

    If this is a good idea, then maybe something like this is too:

  5. Bart van Strien

    If we were to go for stroke/fill functions: The different shapes take different arguments, so the list of arguments will be annoying to document, and annoying to remember. At the moment it's easy to remember circle takes a centre and a radius, and a polygon takes points, with fill it'd take both, depending on the value of the first argument.

    Wrt splitting them up even more, so strokeCircle, etc, that doesn't have the earlier problem, but it does mean doubling all the functions for, in my opinion, questionable benefit. And if ever a third mode were to be added, that would duplicate all primitive drawing functions again, where they all describe the same behaviour. As it is, it selects a behaviour within a shape, rather than a different shape.

    And regarding "autocomplete-targeted" APIs, the biggest downside of that is that, yes, it may make using autocomplete-using IDEs easier to use, it, pretty much by definition, makes non-autocomplete-based editing harder. Now, it wouldn't even be that bad if autocomplete was very accurate and common for lua, but it isn't.

  6. criptych

    Just kind of throwing this out there, but how about a third option? Use single function for each shape, but split setColor into setFillColor and setStrokeColor (perhaps the original function sets both?). Then each shape function draws both fill and stroke, unless the respective color is set to nil. This "avoids the use of an enum" without greatly increasing the number of functions, and could help performance a little in cases where you draw a lot of shapes both filled and stroked (esp. for circle/ellipse as only half the calculations are needed).

  7. Alex Szpakowski

    I think Processing does that, and I'm not a fan of it - especially because it introduces even more global state that users have to be aware of and deal with every single time they call a shape drawing function.

    It also doesn't mix well with my intent to add separate Shape and Line batch objects (which would mainly be separate for implementation reasons).

  8. criptych

    I'm not a fan of it - especially because it introduces even more global state

    Hmm. It wasn't my favorite idea, either, in fact I originally thought to add the colors as parameters to the shape functions instead. But that poses its own problems, like making setColor kind of useless (although I suppose it would play nicer with batch objects); and all but requiring a new Color type, or else the new signature would be pretty unwieldy: e.g. love.graphics.arc(x, y, radius, angle1, angle2, segments, fillR, fillG, fillB, fillA, lineR, lineG, lineB, lineA).

  9. Log in to comment