kivikakk.ee

That depends where you were looking.

Is it a matter of creativity?

Self-imposed limitations?

Wait, this definitely deserves a “wordpress is not livejournal” tag!

性同一性障害(g.i.d.)

とは?

今日、同僚(あるいは友達)のブログを一飲みで読んでる。この人も私も性同一性障害にどうにか煩う。それで少なくともこの痛みは私だけの問題だわけじゃないかわかるのはできる。

g.i.d.について書こう。

私は男で生まれた。このようで生めれたいと私に言われなかったけどそう起こった。

八歳の時、それが違うと始めてわかってた。その日からずっと一緒に歩いてきた。

一回以上一口で(女に)トランスしたがってたけど、やっぱりしてしまうのはいやだ。女じゃないから。だが女と及ばないから男と及ぶわけは全然全然ない。ほんとうはもう少しニュアンスあり。

オフィスで、開発者の同僚は二人で男の人。最近ムービーやゲームとかのモデルが持ってきた。机以上にした。多数ははやっぱり女のモデル。おっぱい大きすぎて、気持ちわるいもん。しょうがないね。

オーダない考えなんだったわ。これからもアンネリと申します。よろしく。


… is?

I’m reading a friend’s blog in a single go today; we both suffer from gender identity disorder in one way or another. With this, at least I can know that this pain isn’t just my problem.

I’ll write about G.I.D.

I was born (physically) male. I didn’t say I wanted to be born this way; it just happened. At 8 years old, I started to realise that it wasn’t right, and since that day I’ve walked hand in hand with that knowledge ’til today.

More than once I’ve wanted to transition (to being female), but in the end I’ve not carried through with the process. Maybe it’s because I’m not female, but not being able to be addressed as female doesn’t mean that I’m male, at all. The truth is a bit more nuanced than that.

At my office, I’ve two male coworkers. Lately they’ve come into some models from movies and games, placing them on their desks, the majority of which are female models; big-breasted and in bad taste. Can’t be helped, right?

These have been unordered thoughts. I’m Anneli from hereon. Nice to meet you.

Short-term goals are ...

.. best kept to oneself until after achieved. amirite?

I spent most of today reading 75 pages of the muse’s1 tumble log2, and it left me with a variety of feelings.

Anything consciousness-raising is good, and that it certainly did. As with any reading of large quantities of “good stuff”, I have the distinct feeling that I wasn’t being vigilant enough; surely reading so much of this type of material should have a transformational effect on a person, leaving me pumped and ready to fight injustice, love myself and be who I want to be. Yada yada.

Alternatively, perhaps not! What it did leave with me was a renewed sense of wanting to improve3, and a vague feeling that the way there is not only knowable, but more and more in the direction I’m headed, so long as I apply myself, bare myself, defend myself …

The steps I’ve taken towards being right with myself over gender have been rewarding so far; I’m “out” as makes sense at work, and while I don’t think I’ve heard anyone call me by (new) name yet4, that will be pretty special.

In the grand scheme of things a name (I suppose) doesn’t seem too special—you’d think with all my complaining about my own use of labels that I wouldn’t accord names so much. But while a label is something one uses to reduce the effort that needs to be expended in working out how to pigeon-hole me5, a name is the identifier that wrests control away from the labeller; it embodies ultimate identity, personality, agency, responsibility.

Whereas any label one can apply to someone is necessarily partial, often or eventually wrong, and usually poorly defined anyway6, a name embodies your imperfections, your divergences from the pigeon-holes: label-centric identification renders them as annoying impurities (“Ashley is a Buddhist, though not one who meditates.”); names just concentrate on the person (“Ashley.”), and let real communication, real learning, real experience take on the rest of the relationship. You can’t have a relationship with someone who’s defined purely in terms of the adjectives you can apply to them.

Being Anneli is empowering. I think partly I exhausted my (birth) name. Arlen is this. Arlen was this. Now Arlen is that. Uh-oh, Arlen was that. Now Arlen is something else. Et cetera. I’m trying to move on from that, though that is in no way necessary or sufficient to decide that I no longer feel the name represents me. There’s a deeper question in there.

My only explanation is that there’s some fighting somewhere inside me7 that rails against the notion of me being “male.” Part of the in-fighting I have (with myself) is that this seems to play into heteronormativity; after all, how can I say “I don’t feel so male, I feel female lots too!” without acknowledging what defines those terms? And frankly that hurts me a bit too; almost like I should be “better than that”8. There’s an alot9 wound up, just in that. Harbinger of heteronormativity’s end by day; reluctant customer by night. Or something.

So dressing ambiguously, wearing hair ambiguously, being named ambiguously10, acting ambiguously; they give me some life. Trans has never been a label11 I’ve been fully comfortable applying to myself for some reason, though I feel more and more that it’s appropriate (… even if I don’t plan on transitioning12). I hate the hair all over my body, and only the futility of fighting it lets me leave it grow out. And when it does, people13 comment on how masculine I look. That kinda kills me.

It’s those kind of experiences that lead me to think that I need to do more in order to broadcast that it’s actually not nice for me to hear things like that; that is, the more work I put into appearing effeminate, the more obvious it will be that I don’t want those comments.

At times like these, I tend to think back to how this plays into heteronormativity14. I’m a bit lost. But I’m finding my way.

  1. Sorry if calling you that makes you feel uncomfortable (should you be reading this)! It’s more a reflection on that you exemplify ideals I strive towards but still fail at practising now much more than I succeed at them.

  2. Does anyone call them that? Just like you’re reading my web log now. Hah.

  3. I nearly used the word “inadequacy” here, but I’ll step out and say: I don’t have any such sense. I don’t feel inadequate in the role I play in anyone’s lives, and where it is close to that line, it’s in my own.

  4. This could have something to do with me being too embarrassed (or something?) to speak louder than a whisper when someone requests clarification on how to pronounce it.

  5. This applies equally whether it is someone else or myself applying the label.

  6. Tell me “what it means to be male” in 20 words or less.

  7. Fighting that, frankly, I’m lucky to be able to give a voice to; I’m sometimes painfully aware (probably not often enough) that the concerns of others are so much bigger than mine that it seems petty in ways to complain about them—but what, does that mean that no one with “bigger” concerns can experience gender dysphoria? No, of course they can; it just gets added onto everything else, too.

  8. (!)

  9. I love you, alot!

  10. Or unambiguously, and as some would say (and I would tell them to go stick their head in a pig), wrongly.

  11. ohnonothoseagain.

  12. Which seems to some people to be as much a part of identifying as trans as actually feeling you’re in the wrong sexed body, as evinced by a friend’s “you’re not actually going to go trans, are you?” when I told them that I was Anneli.

  13. Like my mother.

  14. Why is being effeminate a goal or desire for me? Because it is!

Just a simple matter of changing a key mapping

Or not.

I use a Kinesis Advantage at work. They’re great for RSI-like symptoms, and they’re also programmable. You can remap keys on the fly, and put together macros. This suits me great.

Recently I realised that I never used capslock, and that I used Ctrl-A a lot (in GNU screen), so the obvious solution was to map capslock onto Ctrl-A, consistently saving me a keystroke. I could do this fine with a macro on the keyboard itself—but as it turns out, as long as you have at least one keyboard macro defined, the entire keyboard becomes sluggish and drops keys(!) at high typing speeds.

So, despite the promise of amazing programmability, the keyboard lets itself down here. I figured this shouldn’t be too hard to change in screen itself. Of course, I was wrong.

Capslock is a very special key in X, and it doesn’t appear to have any termcap-like name which I could bind to using bindkey in screen. Instead, you have to remap Capslock to something else entirely.

xmodmap lets you change key mappings—but you can only map one key onto another, not several. I’ll skip the entire story of how I got there, and give the solution instead:

xmodmap -e 'keysym Caps_Lock = Super_L'

Put this in your .bashrc or somewhere else where it’ll get executed on startup. Here we change Caps_Lock to instead behave as Super_L. If you actually use Super_L (winkey?), you’ll be in trouble.

XTerm*vt100.translations: #override \n\
<Key>Super_L: string(0x1b) string("z")

Add this in your .Xresources file. This causes Super_L to instead emit an escape key followed by ‘z’ in xterm. I picked that pretty much at random, but no existing VT100/ANSI escape codes seem to use that. We could just use Caps_Lock here (and skip the xmodmap), but that would result in the shiftlock still being toggled (in addition to our desired action).

If you don’t use xterm, add it to the appropriate resource.

bindkey -d "^[z" command

This goes in .screenrc, and causes the emitted escape sequence on Super_L (Caps_Lock) to act as the command sequence for screen.

Not-so-phantom types

Back before I had a clue what I was doing with OCaml, I read an article on Jane Street Capital’s OCaml blog about using phantom types for static access control—read: totally awesome. I stumbled across a situation that lead me to wonder if I could apply part of that knowledge here.

The short answer is: you can. What am I using it for? Storing the saved status of a record (namely, whether or not it has an id/given primary key associated with it) as a phantom type. I also use the type used for attaching the phantom types to store the primary key itself, which has an associated overhead (and makes the attachee type decidedly not phantom).

The relevant code follows. In my case, the primary keys are of type int32, so they’re what’s buried in the type.

(* pK.ml *)
type none
type some
type ('con,'a) t = int32 option * 'a
let none t = (None,t)
let some k t = (Some k,t)
let get = snd
let pk t = Option.get (fst t)
(* equiv to: match fst t with | Some n -> n | None -> raise Option.No_value *)
let pk_opt = fst

So far, this looks like a pretty standard way to attach a given piece of data to any other piece of data, except for those strange, phantom (not abstract, because there’s no underlying definition) types at the top which never seem to be used, and the similarly unused 'con type variable on t.

The magic happens, of course, in the .mli:

(* pK.mli *)
type none
type some
type ('con,'a) t
val none : 'a -> (none,'a) t
val some : int32 -> 'a -> (some,'a) t
val get : ('con,'a) t -> 'a
val pk : (some,'a) t -> int32
val pk_opt : ('con,'a) t -> int32 option

So, as we recall, the definition of none is let none t = (None,t). The right-hand side matches the definition of t faithfully, as it’s a int32 option * 'a, but we’ve also filled in the 'con type variable, by saying its type is none.

At compile-time, this gets optimised away, because there is no value for the none type. But during compile-time, the type is known.

some is defined as let some k t = (Some k,t), so we know the value k is being stored safely in the int32 option. But the 'con type variable is also specified as some.

Let’s skip ahead and look at pk. It takes a (some,'a) t and yields an int32. That means that, for example, PK.pk (PK.none 42) doesn’t typecheck:

Error: This expression has type (PK.none, int) PK.t
but an expression was expected of type (PK.some, 'a) PK.t

If we omitted the .mli file, we’d get an exception at run-time instead.

It’s important to remember that this technique has nothing to do with the actual bundling of data and subsequent hiding—that’s a perfectly normal thing to do. The benefit here is in making certain assertions about whether or not that data is actually present; we can be sure that PK.pk will never throw an exception, because the object passed to it could only have been created by PK.some.

Note that we do experience some some additional runtime slowness due to the use of an int32 option (and subsequently Option.get or matching on that to retrieve its value). If you’re happy to sacrifice PK.pk_opt, you can do something like this instead:

(* pK.ml *)
type none
type some
type ('con,'a) t = int32 * 'a
let none t = (0l,t)
let some k t = (k,t)
let get = snd
let pk = fst

The .mli is the same, except with pk_opt removed.

This is much more concise, as the boolean status of “is the primary key present?” is not stored at all at runtime. The upshot is that you also have no way to tell at runtime. This isn’t a “problem” in and of itself, because the type-checking means you’ll never accidentally see the 0l value stored with the none type (we just need to put something there, without an option type)—but it means that there’s no way to do anything at runtime that differentiates between the two.

If you don’t need to, then this is great, too, because it’s exactly how you can achieve the static access control, as described in Yaron Minsky’s post referred above—you can also attach additional data if you want to drag information along with the typing data!

So, how am I using this? Here’s an example interface for a record type which has an associated database table:

(* world.mli *)
type base_t = { name: string;
width: int; height: int;
defaultTileId: int32;
placements: placement_t array }
type 'con t = ('con,base_t) PK.t
val empty : PK.none t
val of_id : int32 -> PK.some t
val save : 'con t -> PK.some t

We can ignore the details of this—the base type, 'con t, will either have PK.none or PK.some filled in for 'con.

As an example, there’s a default “empty” record, empty. In the .ml, it’s defined like so:

let empty = PK.none { name="";
width=0; height=0;
defaultTileId=0l;
placements=[||] }

This means that we can’t accidentally treat this as a record that actually has a corresponding row in the database. This has already caught a bug in my application—as soon as I implemented this, the type-checker alerted me where I was allowing users to belong in unsaved worlds, which would cause a problem as soon as I tried to save the user out to the database (and serialise the database ID as zero).

There’s also a certain elegance in the type statement val save : 'con t -> PK.some t, in my opinion.