> Vector2(x=0, y=0) -> Vector(0, 0)

If rgba and uvst are swizzle attributes, are they also accepted as kwargs?

> However, I feel this single scalar is hard to make
a mistake with accidentally passing in the wrong thing?

I don't think so. I think it could easily happen accidentally, while
refactoring.

On Tue, 27 Feb 2018, 18:19 René Dudfield, <ren...@gmail.com> wrote:

> Some good points. Thanks, I appreciate the discussion.
>
>
> On Tue, Feb 27, 2018 at 3:51 PM, Daniel Pope <ma...@mauveweb.co.uk> wrote:
>
>> > Single scalar constructor should Vector2(1) == Vector2(1, 1)
>>
>> This is the kind of situation where I'd follow PEP20: "In the face of
>> ambiguity, refuse the temptation to guess." There's an obvious pitfall if
>> you expected to pass a tuple and you instead pass a scalar or the wrong
>> length tuple - it silently succeeds but constructs the wrong Vector.
>> Perhaps raise a TypeError?
>>
>>
> At the moment Vector2/3 uses keyword arguments.
> Vector2() -> Vector(0, 0)
> ​Vector2(x=0, y=0) -> Vector(0, 0)
> Vector2(1) -> Vector(1, 0)
>
> I'm beginning to think keyword arguments are wrong for this.
> Would maybe prefer to raise a TypeError as you suggest,
>   or follow GLSL behaviour and allow single scalar, error for the others.
>
> These should raise an error for sure?
>   Vector3(1, 1) # oops, I meant to type three 1s.
>   Vector3(some2d_I_thought_was_a_3d) #oops, the incoming value is of a
> different size.
>
> However, I feel this single scalar is hard to make
> a mistake with accidentally passing in the wrong thing?
>   Vector(1)
>
> Keyword arguments are also pretty useless for readability with Vector2/3.
> Because you know it's a 3 element container.
>   Vector3(x=0, y=0, z=0) VS
>   Vector3(0,0,0)
>
> It's fairly common to init vec2/vec3 in GLSL with a single number.
> Eyeballing a few scripts, maybe 10% of usage is single scalar constructor.
> And to be able to have fairly good compatibility with code from shadertoy
> might be nice.
>
>
>
>
>
> > Lower dimensional to higher dimension contructors should work:
>> > Vector3(1, Vector2(2, 3)) == Vector3(1, 2, 3)
>>
>> We don't need this because we have star args:
>>
>> Vector3(1, *Vector2(2, 3))
>>
>
> Yeah, good point.
>
> There is this error message for this case at least:
>     >>> Vector3(1, (1,2))
>     ValueError: Vector3 must be initialized with 3 real numbers or a
> sequence of 3 real numbers
>
> I don't think the "Lower dimensional to higher dimension constructors
> should work" bit is that important.
> It's not super common in GLSL code I've seen in the wild anyway.
>
> And as you say, we have * notation for this.
>
>
>
>
>
>
> *Some more benchmarking.*
>
> Some timing on python 3.6 (with PyArg_ParseTupleAndKeywords which supports
> keyword arguments).
> Note v3.xyz is the fastest constructor. See below with just
> PyArg_ParseTuple (no speed improvement).
>
>
> v3 = Vector3(0)
>
> %timeit v3.xyz
>
> 10000000 loops, best of 3: *83.3 ns per loop*
>
> %timeit Vector3()
> 10000000 loops, best of 3: 131 ns per loop
>
> %timeit Vector3(0)
> 1000000 loops, best of 3: 199 ns per loop
>
> %timeit Vector3(0, 0, 0)
> 1000000 loops, best of 3: 269 ns per loop
>
> %timeit Vector3(x=0, y=0, z=0)
> 1000000 loops, best of 3: 426 ns per loop
>
> %timeit Rect((0, 0, 0, 0))
> 10000000 loops, best of 3: 184 ns per loop
>
> from numpy import array
> %timeit array((0,0,0))
> 1000000 loops, best of 3: *919 ns* per loop
>
> assert id(v3) != id(v3.xyz), ".xyz makes a copy"
>
> %timeit (0,0,0)
> 100000000 loops, best of 3: *14.9 ns* per loop
>
> somevec= (1, 2)
>
> %timeit Vector3(1, *somevec)
> 1000000 loops, best of 3: 333 ns per loop
>
> %timeit anothervec=v3.xyz;anothervec.xyz = (1, 2, 3)
> 1000000 loops, best of 3: 221 ns per loop
>
>
>
>
>
> *Now timing with PyArg_ParseTuple.*
> Interestingly, in 3.6 PyArg_ParseTupleAndKeywords and PyArg_ParseTuple
> are the same speed (on this mac laptop anyway).
>
> %timeit Vector3(0)
> 1000000 loops, best of 3: 198 ns per loop
>
> %timeit Vector3(0, 0, 0)
> 1000000 loops, best of 3: 276 ns per loop
>
>
> Exactly the same timing as PyArg_ParseTupleAndKeywords pretty much.
>
>
> And now for something kind of funny...
>
> In [11]: from dis import dis
>
> In [12]: def a():
>     ...:     Vector3(0,0,0)
>     ...:
>
> In [13]: def b():
>     ...:     v3.xyz
>     ...:
>
> In [14]: dis(a)
>   2           0 LOAD_GLOBAL              0 (Vector3)
>               2 LOAD_CONST               1 (0)
>               4 LOAD_CONST               1 (0)
>               6 LOAD_CONST               1 (0)
>               8 CALL_FUNCTION            3
>              10 POP_TOP
>              12 LOAD_CONST               0 (None)
>              14 RETURN_VALUE
>
> In [15]: dis(b)
>   2           0 LOAD_GLOBAL              0 (v3)
>               2 LOAD_ATTR                1 (xyz)
>               4 POP_TOP
>               6 LOAD_CONST               0 (None)
>               8 RETURN_VALUE
>
> An ugly hack would be to
>   avoid those byte code ops,
>   and avoid PyArg_ParseTupleX in CALL_FUNCTION...
>
> And encode numbers in a swizzle-ish attribute.
>   Vector3.xyz_1234234235__23423__333 -> Vector3(1234234235, 23423, 333)
>
> Haha... pretty ridiculous. Not a good idea for readability.
> But interesting how you can abuse the attribute getter.
>
>
> It's sort of unfair that tuple construction gets a 18x faster constructor
> over extension types in CPython.
> But anyway. 3.4x to 11x faster construction than numpy arrays is nice.
>
>

Reply via email to